# Code Dart server apps pour Steganosaurus ###### tags: `DGSE` `2020` `Brigitte_Friang` `Steganosaurus` `CTF` Ce code Dart permet de debugger et comprendre comment fonctionne l'application du challenge du CTF de la DGSE de 2020. Un write Up ce trouve [ici](https://hackmd.io/2S0GPkLqQkGAokm0_e2-7Q). Ce premier code permet de convertire l'image en string binaire et de la sauvegarder dans un fichier `flag.bin`. Comme cette partie du code peut être long suivant l'image, autant le faire une seule fois. ```dart=0 import 'dart:io'; import 'package:image/image.dart'; void main() { Image image = decodeImage(File('flag.png').readAsBytesSync()); String bbggrrString; String pixelString; String rrggbbString = ""; for (int i = 0; i < image.length; i++) { bbggrrString = image[i].toRadixString(2).padLeft(32, '0').substring(8); pixelString = bbggrrString.substring(16, 24) + bbggrrString.substring(8, 16) + bbggrrString.substring(0, 8); rrggbbString += pixelString; } new File('flag.bin').writeAsString(rrggbbString); } ``` Ce deuxième code est celui de l'application pour du server apps: ```dart=0 import 'dart:convert'; import 'dart:io'; import 'package:image/image.dart'; void main() { steggapp(); } String messageToBinaryString(String pMessage) { String result = ""; List<int> bytes = utf8.encode(pMessage); bytes.forEach((item) { result += item.toRadixString(2).padLeft(8, '0'); }); return result; } void steggapp() { String messageToHide = messageToBinaryString('DGSEESIEE{FL4GISH3R3}'); Image aimage = decodeImage(File('flag_empty.png').readAsBytesSync()); Image resisedImage = copyResize(aimage, width: 1000); new File('flag.bin').readAsString().then((String rrggbbString) { int messageLength = 0; var offsetArray = new List(); int offsetToStore; int lengthToStore; int offset; String subStringToHide = messageToHide.substring(0, 1); String rrggbbSubString = rrggbbString.substring((rrggbbString.length / 4).round()); // Recherche des couples offset-taille while (messageLength < messageToHide.length) { offsetToStore = rrggbbSubString.indexOf(subStringToHide); while (offsetToStore != -1 && subStringToHide.length <= messageToHide.length - 1) { lengthToStore = subStringToHide.length; offset = offsetToStore; subStringToHide = messageToHide.substring(0, subStringToHide.length + 1); offsetToStore = rrggbbSubString.indexOf(subStringToHide); } if (subStringToHide.length == messageToHide.length) { int lastOffsetToStore = rrggbbSubString.indexOf(subStringToHide); if (lastOffsetToStore == -1) { offsetArray.add([offset, lengthToStore]); offsetArray.add([rrggbbSubString.indexOf(subStringToHide[-1]), 1]); } else { offsetArray.add([ rrggbbSubString.indexOf(subStringToHide), subStringToHide.length ]); } messageLength += subStringToHide.length; } else { messageToHide = messageToHide.substring(subStringToHide.length - 1); messageLength += subStringToHide.length; offsetArray.add([offset, lengthToStore]); offsetToStore = 0; lengthToStore = 1; offset = 0; subStringToHide = messageToHide.substring(0, 1); } } // Ecriture des couples offset-taille dans une string binaire int offsetDataSize = resisedImage.length * 8 * 3; // 514000 * 8 * 3 = 12336000 // 12336000 = 101111000011101110000000 codé sur 24 bits donc datasizebit = 24 int offsetDataSizeBit = offsetDataSize.toRadixString(2).length; // Même méthode ici, mais avec la longueur du message à cacher. int messageToHideLenghtSizeBit = messageToHide.length.toRadixString(2).length; // 7 // On écrit deux paquets de 24 bits, un représente la taille des couples offset-taille // Un autre représente le nombre de bits sur lequel sont codés les tailles des couples offset-taille String stringToWrite = offsetArray.length .toRadixString(2) .padLeft(offsetDataSizeBit, '0'); stringToWrite += messageToHideLenghtSizeBit.toRadixString(2).padLeft( offsetDataSizeBit, '0'); offsetArray.forEach((listOfData) { listOfData.forEach((data) { // On écrit les couples offset taille. stringToWrite += listOfData[0].toRadixString(2).padLeft(offsetDataSizeBit, '0') + listOfData[1] .toRadixString(2) .padLeft(messageToHideLenghtSizeBit, '0'); }); }); List<int> pixelValue = new List(); int compteur = 0; int missingSize; String finaleImageString = stringToWrite + rrggbbString.substring(stringToWrite.length); int limit = stringToWrite.length; // Transforme le message binaire en pixel while (compteur < limit) { try { // print(compteur); pixelValue.add(int.parse(stringToWrite.substring(0, 8), radix: 2)); // 8 bits to int stringToWrite = stringToWrite.substring(8); compteur += 8; } on RangeError { // SI il manque des bits pour une couleur de pixel, on complete avec les bits de l'image original missingSize = 8 - stringToWrite.length; pixelValue.add(int.parse( stringToWrite + finaleImageString.substring(compteur + stringToWrite.length, compteur + stringToWrite.length + missingSize), radix: 2)); compteur += 8; } } // Ecriture des pixel dans la nouvelle image Image imageToSave; int compteurPixel; imageToSave = resisedImage.clone(); compteurPixel = 0; List<int> lastPixelList = new List(); for (int iz = 0; iz < pixelValue.length; iz += 3) { // On écrit pixel par pixel. Un pixel fait 3*8 bits (sans compter l'alpha) try { imageToSave.data[compteurPixel] = getColor(pixelValue[iz], pixelValue[iz + 1], pixelValue[iz + 2]); compteurPixel += 1; } on RangeError { // Si les données à ecrire dépasse les 3*8 bits de couleurs pour le dernier pixel, on prend les bits originaux pixelValue = pixelValue.sublist(iz); var basixPixelList = imageToSave.data[compteurPixel] .toRadixString(2) .padLeft(32, '0') .substring(8); int redChannelint = int.parse(basixPixelList.substring(16, 24), radix: 2); int greenChannelint = int.parse(basixPixelList.substring(16, 24), radix: 2); int blueChannelint = int.parse(basixPixelList.substring(16, 24), radix: 2); List<int> originalpixelvalue = [ redChannelint, greenChannelint, blueChannelint ]; for (int ze = 0; ze <= 2; ze++) { if (ze > pixelValue.length - 1) { lastPixelList.add(originalpixelvalue[ze]); } else { lastPixelList.add(pixelValue[ze]); } } imageToSave.data[compteurPixel] = getColor(lastPixelList[0], lastPixelList[1], lastPixelList[2]); } } new File('out.png')..writeAsBytesSync(encodePng(imageToSave)); }); } ```