---
# System prepended metadata

title: Code Dart server apps pour Steganosaurus
tags: [CTF, DGSE, Brigitte_Friang, '2020', Steganosaurus]

---

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

```