# 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));
});
}
```