Solution de DJYoloSwag07 pour Silence

forensics android

11 novembre 2025

Pour ce challenge, nous sommes en possession d’une sauvegarde exportée de l’application de messagerie Silence contenant plusieurs fichiers .xml et de bases de données Sqlite.

$ tree SilenceExport/
SilenceExport/
├── cache
├── code_cache
├── databases
│   ├── _jobqueue-SilenceJobs
│   ├── _jobqueue-SilenceJobs-journal
│   ├── canonical_address.db
│   ├── canonical_address.db-journal
│   ├── messages.db
│   └── messages.db-journal
├── files
│   └── sessions-v2
│       └── 3
└── shared_prefs
    ├── SecureSMS-Preferences.xml
    ├── SecureSMS.xml
    └── org.smssecure.smssecure_preferences.xml

En chargeant la base de donnée messages.db dans sqlite3, on se rend compte que les messages sont chiffrés et illisibles.

Pour tenter de déchiffrer ces messages, j’ai utilisé l’outil BreakTheSilence (https://github.com/hydrargyrum/breakthesilence)

J’ai d’abord tenté de modifier le script shell lançant le programme pour itérer de 00000 à 99999, mais cela étant trop lent j’ai plutot modifié directement le code source en java pour tester toutes les valeurs possibles.

diff --git a/src/re/indigo/breakthesilence/MasterSecretUtil.java b/src/re/indigo/breakthesilence/MasterSecretUtil.java
index c5bf347..61ddfe6 100644
--- a/src/re/indigo/breakthesilence/MasterSecretUtil.java
+++ b/src/re/indigo/breakthesilence/MasterSecretUtil.java
@@ -275,50 +275,41 @@ public class MasterSecretUtil {
 
     String userPassphrase;
 
-    if (System.console() != null) {
-      userPassphrase = new String(System.console().readPassword("Password (leave empty if empty): "));
-    } else {
-      System.err.println("No console, reading password from stdin.");
-      BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
-      try {
-        userPassphrase = buffer.readLine();
-      } catch (IOException exc) {
-        System.err.println("Can't read stdin");
-        exc.printStackTrace(System.err);
-        System.exit(74);
+    for (int i = 0000; i < 100000; i++)
+    {
+        userPassphrase = String.format("%05d", i);
+        System.err.println("Testing " + userPassphrase + "...");
+
+        if (userPassphrase.isEmpty()) {
+            userPassphrase = UNENCRYPTED_PASSPHRASE;
+        }
+
+        InputData silProps = new InputData();
+        silProps.passphrase_iterations = Integer.parseInt(props.getProperty("passphrase_iterations"));
+        silProps.master_secret = Base64.getDecoder().decode(props.getProperty("master_secret"));
+        silProps.mac_salt = Base64.getDecoder().decode(props.getProperty("mac_salt"));
+        silProps.encryption_salt = Base64.getDecoder().decode(props.getProperty("encryption_salt"));
+        silProps.user_passphrase = userPassphrase;
+
+        MasterSecret sec;
+        try {
+            sec = getMasterSecret(silProps, silProps.user_passphrase);
+        } catch (InvalidPassphraseException exc) {
+            System.err.println("Invalid passphrase!");
+            continue;
+        } catch (GeneralSecurityException exc) {
+            exc.printStackTrace(System.err);
+            System.exit(1);
+            return;
+        } catch (IOException exc) {
+            exc.printStackTrace(System.err);
+            System.exit(74);
+            return;
+        }
+
+        System.out.println("encryption_key = " + Base64.getEncoder().encodeToString(sec.encryptionKey));
+        System.out.println("mac_key = " + Base64.getEncoder().encodeToString(sec.macKey));
         return;
-      }
-    }
-
-    if (userPassphrase.isEmpty()) {
-      userPassphrase = UNENCRYPTED_PASSPHRASE;
     }
-
-    InputData silProps = new InputData();
-    silProps.passphrase_iterations = Integer.parseInt(props.getProperty("passphrase_iterations"));
-    silProps.master_secret = Base64.getDecoder().decode(props.getProperty("master_secret"));
-    silProps.mac_salt = Base64.getDecoder().decode(props.getProperty("mac_salt"));
-    silProps.encryption_salt = Base64.getDecoder().decode(props.getProperty("encryption_salt"));
-    silProps.user_passphrase = userPassphrase;
-
-    MasterSecret sec;
-    try {
-       sec = getMasterSecret(silProps, silProps.user_passphrase);
-    } catch (InvalidPassphraseException exc) {
-      System.err.println("Invalid passphrase!");
-      System.exit(65);
-      return;
-    } catch (GeneralSecurityException exc) {
-      exc.printStackTrace(System.err);
-      System.exit(1);
-      return;
-    } catch (IOException exc) {
-      exc.printStackTrace(System.err);
-      System.exit(74);
-      return;
-    }
-
-    System.out.println("encryption_key = " + Base64.getEncoder().encodeToString(sec.encryptionKey));
-    System.out.println("mac_key = " + Base64.getEncoder().encodeToString(sec.macKey));
   }
 }

On obtient la sortie suivante après quelques secondes:

[...]
Testing 56844...
Invalid passphrase!
Testing 56845...
Invalid passphrase!
Testing 56846...
Invalid passphrase!
Testing 56847...
Invalid passphrase!
Testing 56848...
Invalid passphrase!
Testing 56849...
Enter output of run-jar.sh:
OK, successfully read properties.
Proceeding to conversion, this may take a while, please wait!
Done!

À l’aide d’un petit coup de grep, on trouve le flag dans le json sorti par l’outil :)