ThaySan
  • 👋Bienvenue
    • Avant-propos
  • 🚩CTF & Writeups
    • 2025 | EC2
      • Let's Crax
    • 2025 | HackDay
      • 🔑Cryptographie
        • Drunk Christmas
        • Find Eve 1
        • Well hidden message - Standard Code Encryption
      • 🔎Forensic
        • Copperwire Extraction
        • Distracted user
        • I believe you can't fly
      • 🧠Misc
        • Hello Steve
      • 💾Programmation
        • Lonely bot
        • Lonely bot #2
        • Lonely bot #3
        • Useless Animals Sorting
        • Who cares about SSI anyway ?
      • ⚙️Reverse
        • Just dig
        • Rusty_rev
        • The Cogs of Blackmail
      • 🎭Steganographie
        • It says a lot when there is no music
        • Mona LSB
        • Well hidden message - Insignificant blue
      • 🌐Web
        • Super Website Verificator 3000
        • The analytical engine leak
        • The Watchful Gears: Uncover the Secrets Within
        • Your region's finest
    • 2024 | Efrei - CyberNight
      • 🔑Cryptographie
        • Clavier spécial
        • Le futur
        • Securechain 30.0
        • Cascade
        • Shared Flag
        • Weird Algorithm
      • 🧊Minecraft
        • Introduction
        • Non aux Bouquins Trafiqués
        • Redstone Gold Block
      • 💾Programmation
        • Captcha 1.0
        • Intro à la prog
        • Captcha 2.0
      • ⚙️Reverse
        • Reverse the Reverse
        • Find me if you can
        • HuGO Decrypt
        • Kitten eXORcism
        • M30W Vault Tech
        • The Ugandan Labyrinth
      • 🎭Stéganographie
        • Le message
        • bon Le ordre
        • COD FORFLAG
        • Mauvaise note
        • Bruit
        • Un (un ?) drôle de QR code
        • Randonnée Guillerette à Bordeaux
      • 💻Système
        • Marche-pied
        • Escabot
        • régulation des Données et des Normes de Sécurité
      • 🌐Web
        • cybernight.zip
        • Mon champion préféré
        • Co(mpressed)okies
        • Gitty Mistake
        • JWT Kiddo
        • Parseur Farceur
      • L'enquête
        • L'enquête 2/6
        • L'Enquête 1/6
        • Bienvenue, enquêteur
    • 2024 | Star-Hack
      • 🔑Cryptographie
        • César, mais pas César
        • Double ennui
        • Langage secret
        • Quadratique Mystérieuse
        • ReSultAt
        • Sup3r S3cr3t
        • Warmup
      • 🔎Forensic
        • Cache-cache
        • Fichier ZIP protégé par mot de passe
        • HEADER
        • Investigation 1
        • Investigation 2
      • 🧠Misc
        • B4l4d3 Urb41n3
        • Bruhh, c'est quoi ça ?
        • Cut13
        • Pika Pika
      • 😈Pwn
        • Pwn0x01
        • Pwn0x02
        • Pwn0x03
      • ⚙️Reverse
        • Assembly
        • Rev0x00
        • Rev0x01
        • Rev0x02
      • 🌐Web
        • Clone Udemy
        • Flask
        • Guess_The_Passcode
        • PHP
        • Tickets
        • Usine de Cookies
    • 2024 | ECW
      • 🔑Cryptographie
        • Course hipPIN
    • 2024 | CTFREI Intro
      • 🔑Cryptographie
        • AES Intro
        • Aléatoire
        • Game of Luck
        • RSA Intro
        • RSA2
        • RSA3
      • 🔎Forensic
        • Mais qui est le photographe ?
        • Mais où est passé mon flag ?
        • Mémoire 1/4
        • Mémoire 2/4
        • Mémoire 3/4
        • Mémoire 4/4
        • My computer is talking
      • 📚OSINT
        • Avion ✈
        • Geoint
        • Google!
        • Googlint
        • Le pivot
        • Le temps commence maintenant
        • Sacré dossier
        • Socint
      • 💾Programmation
        • Try Me
        • Answer Me
        • Eval Me
        • Time Based
      • 😈Pwn
        • BOF Intro
        • Shop
        • BOF 2
        • BOF win()
      • ⚙️Reverse
        • CrackMe1
        • CrackMe2
        • CrackMe3
        • Hidden...
        • Something changed?
        • ZZZ
      • 🎭Stéganographie
        • Cybernight être comme
        • Joli paysage
        • Petit poisson
        • StegHide 'n' Seek
        • Un canard pas comme les autres
      • 💻Système
        • Bash Jail
        • Bash Jail Revenge
        • BrokenBin
        • GTFO Of Here
        • Pyjail
        • Pyjail Revenge
        • Strange input, right?
      • 🌐Web
        • SQLi
        • POST This Money
        • Give me my Flask PIN
        • Access
        • Render
        • RenderV2
        • Touchy
    • 2024 | DefCamp
      • 🔑Cryptographie
        • conv
        • oracle-srl
        • ctr
      • 🔎Forensic
        • i-got-a-virus
        • Alternating
        • call-me-pliz
      • 🧠Misc
        • pyterm
      • 📱Mobile
        • mobisec
      • 📚OSINT
      • 😈Pwn
      • ⚙️Reverse
      • 🕵️Traque
      • 🌐Web
        • noogle
        • production-bay
    • 2024 | 404CTF
      • 🔑Cryptographie
        • Bébé nageur
        • Le petit bain
        • Poor Random Number Generator [1/2]
        • Plongeon Rapide Super Artistique
        • J'éponge donc j'essuie
        • Poor Random Number Generator [2/2]
        • La Seine
        • J'ai glissé chef !
        • SEA - La face cachée de l'Iceberg
      • 🔎Forensic
        • Le tir aux logs
        • Darts Bank
        • Vaut mieux sécuriser que guérir
        • De bons croissants au beurre
        • Poids Raw vs. Cours Jette [1/3]
      • 🔌Hardware
        • Serial killer
        • Le soulevé de GND
        • Comment est votre modulation ? [1/2]
        • Sea side channel [1/4] - Introduction
        • Comment est votre modulation ? [2/2]
        • Sea side channel [2/4] - Reconnaissance
        • Sea side channel [3/4] - Mais où sont les triggers ?
      • 🤖IA
        • Du poison [1/2]
        • Du poison [2/2]
        • Des portes dérobées
      • 🧠Misc
        • Discord
        • De la friture sur la ligne
        • Bienvenue
        • Revers(ibl)e Engineering [0/2]
      • 📚OSINT
        • Légende
        • Not on my watch
        • Secret Training [1/2]
      • 😈Pwn
        • Pseudoverflow
        • Jean Pile
        • Mordu du 100m
        • Antismash
      • 🐈‍⬛Quantique
        • Des trains superposés
        • De l'écoute, pas très discrète
        • De la multiplicité des problèmes
      • ⚙️Reverse
        • ⭐Échauffement
        • ⭐Intronisation du CHAUSSURE
        • ⭐Bugdroid Fight [1/2]
        • ⭐Revers(ibl)e Engineering [1/2]
        • ⭐Bugdroid Fight [2/2]
        • ⭐Nanocombattants
        • ⭐Revers(ibl)e Engineering [2/2]
        • Le Tableau Noir
      • 🎭Stéganographie
        • ⭐L'absence
        • ⭐Regarder en stéréo
        • ⭐La Barre Fixe
        • ⭐Le grand écart
        • ⭐La chute
      • 🌐Web
        • ⭐Vous êtes en RETARD
        • ⭐Le match du siècle [1/2]
        • ⭐Exploit mag
        • ⭐Le match du siècle [2/2]
        • ⭐LE GORFOU 42
        • ⭐La boutique officielle
    • 2024 | CTFREI - Bordeaux
      • 🔑Cryptographie
        • zzz
      • 📚OSINT
        • Alexis Dumas
        • Back to the bureau
        • Dr Octopus
        • Folie et ambition
        • GeoGuessr
        • Hugo Nelots : prélude
        • La fin ?
        • La fuite Dumas
        • Un réseau suspect
      • 💾Programmation
        • Eval me 1
        • Eval me 2
        • Time Based
      • 💻Système
        • Broken Binary 1
        • Broken Binary 2
        • GTFO of here
        • Pyjail 1
        • Pyjail 2
        • Pyjail 3
        • Pyjail 4
      • 🌐Web
        • Au commencement était le verb
        • Becadmin
        • PHP Juggler
    • 2024 | HTB - Cyber Apocalypse Challenges
      • 🔗Blockchain
        • Lucky Faucet
        • Recovery
        • Russian Roulette
      • 🔑Cryptographie
        • Blunt
        • Dynastic
        • Iced TEA
        • Makeshift
        • Primary Knowledge
      • 🔎Forensic
        • An unusual sighting
        • Data Siege
        • Fake Boost
        • Game Invitation
        • It Has Begun
        • Phreaky
        • Pursue The Tracks
        • Urgent
      • 🔌Hardware
        • BunnyPass
        • Flash-ing Logs
        • Maze
        • Rids
        • The PROM
      • 🧠Misc
        • Character
        • Cubicle Riddle
        • Path of Survival
        • Stop Drop and Roll
        • Unbreakable
        • Were Pickle Phreaks
        • Were Pickle Phreaks Revenge
      • 😈Pwn
        • Delulu
        • Pet Companion
        • Tutorial
        • Writing on the Wall
      • ⚙️Reverse
        • BoxCutter
        • Crushing
        • FollowThePath
        • LootStash
        • MazeOfPower
        • Metagaming
        • PackedAway
        • QuickScan
      • 🌐Web
        • Flag Command
        • KORP Terminal
        • Labyrinth Linguist
        • LockTalk
        • Testimonial
        • TimeKORP
    • 2024 | UNbreakable
      • 🔑Cryptographie
        • start-enc
        • traffic-e
      • 🔎Forensic
        • easy-hide
        • password-manager-is-a-must
      • 🧠Misc
        • rfc-meta
      • 📱Mobile
        • flagen
        • improper-configuration
      • 📡Network
        • wifi-basic
        • wifiland
      • 📚OSINT
        • persistent-reccon
        • safe-password
      • 😈Pwn
        • intro-to-assembly
      • ⚙️Reverse
        • fake-add
      • 🎭Stéganographie
        • secrets-of-winter
      • 🌐Web
        • pygment
        • sided-curl
        • you-can-trust-me
    • 2023 | EFREI - CyberNight
      • 📚OSINT
        • Invest Now !
      • 😈Pwn
        • NSA Call Converter
      • ⚙️Reverse
        • CryptoVirus
        • WebChaussettes
      • 🌐Web
        • DoctoLeak
    • 2023 | Flag4All
      • 🔑Cryptographie
        • Aes IV
        • Crypt my loop
        • Kentucky fried chicken
        • RSA primes
        • Xor
    • 2022 | EFREI - CyberNight
      • 🔑Cryptographie
        • Coupé-décalé
        • ExFILEtration
        • Il s'est baissé ou pas
        • J'ai pas roté
        • Les allemands !
        • RSA Strong Prime generator
      • 🔎Forensic
        • Bomberman 1/2
        • Bomberman 2/2
        • Magic
        • Peu importe le chemin
        • Sniff sniff
        • Souvenir
        • Xray
      • 🔌Hardware
        • Class4
        • Find me 2/3
        • Identify 1/3
        • Yo listen 3/3
      • 🧠Misc
        • Et je tombe tombe tombe
        • Des yeux partout
        • RiGOLe
        • Roomba tricheur
        • Survey
        • Tinder
      • 💾Programmation
        • Repeat
        • Startup
        • Timing
      • ⚙️Reverse
        • Auth 1
        • Auth2
        • Auth3
        • Cryptoroomba
        • Tenet
      • 🎭Stéganographie
        • 50 shades of stephane legar
        • Chess master
        • Deviens champion sers toi de tout ce que tu as appris
        • Drifting in the bits
        • Pyramide
        • Spirale
      • 🌐Web
        • Ah bah c'est du propre
        • Cooking roomba
        • Leaderboard
        • vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
Propulsé par GitBook
Sur cette page
  • Challenge
  • Solution
  • Reverse de l'application
  • Récupération des comptes existants
  • Cassage de mot de passe
  • Récupération des secrets

Cet article vous a-t-il été utile ?

  1. CTF & Writeups
  2. 2024 | DefCamp
  3. Mobile

mobisec

PrécédentMobileSuivantOSINT

Dernière mise à jour il y a 7 mois

Cet article vous a-t-il été utile ?

Catégorie: Mobile Difficulté: Moyen Flag: CTF{77cd55d22ef0d516a45ed0e238fbc5dbc4c93b0824047ea3e0a0509a5a9735ac}

Challenge

Description


Secure note-taking app.

You are given a wordlist. Furthermore rockyou.txt may be of use.

Note that the initial data on the server was stored differently, and decryption should take in consideration:

nonce, tag, ciphertext = encrypted_data[:16], encrypted_data[16:32], encrypted_data[32:]

Use pycryptodome and default key derivation hashing algorithm.

Ce challenge tourne sur un docker et n'est pas disponible

Solution

La première chose à faire est de décompiler l'apk. Dans sources/com/example/flagen on trouve les fichiers Java important.

Reverse de l'application

Dans NotesActivity.java on trouve la fonction qui sert à faire les requêtes HTTP, on voit qu'elle ajoute l'entête X-MOBISEC=ef75826d9de13292593aa57f82a7763d et un identifiant unique de type UUID à la fin de l'url

public final HttpURLConnection n(String method, String path) {
    StringBuilder url = new StringBuilder("http://");
    url.append(this.host);
    url.append(":");
    url.append(this.port);
    url.append(path);
    SharedPreferences sharedPreferences = getSharedPreferences("unique_id_prefs", 0);
    String uniqueId = sharedPreferences.getString("unique_id", (String) null);
    
    // Création du UUID si aucun n'est définit dans les préférences
    if (uniqueId == null) {
        uniqueId = UUID.randomUUID().toString();
        SharedPreferences.Editor prefEdit = sharedPreferences.edit();
        prefEdit.putString("unique_id", uniqueId);
        prefEdit.apply();
    }
    
    // Ajout du UUID
    url.append(uniqueId);
    HttpURLConnection httpURLConnection = (HttpURLConnection) new URL(url.toString()).openConnection();
    httpURLConnection.setConnectTimeout(20000);
    httpURLConnection.setReadTimeout(20000);
    httpURLConnection.setRequestMethod(method);
    // Ajout de l'entête
    httpURLConnection.setRequestProperty("X-MOBISEC", "ef75826d9de13292593aa57f82a7763d");
    httpURLConnection.setRequestProperty("Accept", "application/json");
    return httpURLConnection;
}

Une autre fonction intéressante est celle qui sert de hashage :

public static String o(String str) {
    try {
        byte[] digest = MessageDigest.getInstance("SHA-256").digest(("LbhXabjVaCenpgvprFnygfNerHavdhrylTrarengrqSbeRirelCnffOhgVzGbbYnmlGbPbqrGung:)" + str).getBytes());
        StringBuilder hexFormat = new StringBuilder();
        for (byte b : digest) {
            String hex = Integer.toHexString(b & 255);
            if (hex.length() == 1) hexFormat.append("0");
            hexFormat.append(hex);
        }
        return hexFormat.toString();
    } catch (NoSuchAlgorithmException e) {
        throw new RuntimeException(e);
    }
}

En cherchant les fichiers utilisant NotesActivity, on trouve sources\z0\a.java qui utilise la fonction de requêtes HTTP pour faire un GET sur l'endpoint /api/v1/acc/pass/.

String hash = new JSONObject(sb.toString()).getJSONObject("secret").getString("hash");
String password = ((TextView) notesActivity.findViewById(R.id.password)).getText().toString();
if (!hash.isEmpty()) {
    if (!NotesActivity.o(password).equals(hash)) {
        new Handler(Looper.getMainLooper()).post(new e(8, notesActivity));
    }
}
notesActivity.password = password;

Ce passage vérifie que le hash du password entré est le même que celui renvoyé par le serveur.

On a également une fonction intérressante dans le même fichier :

HttpURLConnection request = notesActivity3.n("GET", "/api/v1/sec/");
BufferedReader bufferedReader2 = new BufferedReader(new InputStreamReader(request.getInputStream()));
StringBuilder response = new StringBuilder();
while (true) {
    String readLine2 = bufferedReader2.readLine();
    if (readLine2 != null) {
        response.append(readLine2);
    } else {
        request.disconnect();
        ((TextView) notesActivity3.findViewById(R.id.secretText)).setText(new String(z1.a.J(notesActivity3.password, Base64.decode(new JSONObject(response.toString()).getJSONObject("secret").getString("text"), 0)), StandardCharsets.UTF_8));
    }
}

Ici on récupère un secret sur le serveur, on le décode en base64 puis on le passe dans la fonction z1.a.J() avec le mot de passe. Pour déchiffrer un secret on a donc visiblement besoin des mots de passe.

Regardons cette fonction :

public static byte[] J(String password, byte[] ciphertext) {
    byte[] salt= "0123456789abcdef".getBytes();
    byte[] nonce = Arrays.copyOfRange(ciphertext, 0, 12);
    byte[] cipher_tag= Arrays.copyOfRange(ciphertext, 12, ciphertext.length);
    SecretKeySpec secretKeySpec = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(new PBEKeySpec(password.toCharArray(), salt, 100000, 256)).getEncoded(), "AES");
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    cipher.init(2, secretKeySpec, new GCMParameterSpec(128, nonce));
    return cipher.doFinal(cipher_tag);
}

On utilise PBKDF2 (une méthode pour dériver un secret) avec la fonction de hashage SHA256, le sel 0123456789abcdef et 100000 itérations. On génère un secret dérivé de 256 bits.

Ce secret dérivé est utilisé pour déchiffrer avec de l'AES en mode GCM. Le nonce du GCM est situé sur les 12 premiers octets du ciphertext, on a également le tag (qui sert de vérification) situé sur les 16 derniers octets. Le véritable ciphertext est situé entre les deux. En gros :

nonce, ciphertext, tag = ciphertext[:12], ciphertext[12:-16], ciphertext[-16:]

Récupération des comptes existants

On va tester les UUID présents dans wordlist.txt pour récupérer ceux qui possède un hash et un secret :

import json
import requests

HOST = '35.242.231.98'
PORT = 30512


def request(method: str, path: str, uuid: str):
  headers = {
    'X-MOBISEC': 'ef75826d9de13292593aa57f82a7763d',
    'Accept': 'application/json'
  }
  url = f'http://{HOST}:{PORT}{path}{uuid}'
  return requests.request(method=method, url=url, headers=headers).json()


def main():
  with open('wordlist.txt', 'r') as f:
    uuids = f.read().splitlines()
  accounts = []
  for uuid in uuids:
    _hash = request('GET', '/api/v1/acc/pass/', uuid)['secret']['hash']
    if _hash:
      account = {'uuid': uuid, 'hash': _hash}
      _secret = request('GET', '/api/v1/sec/', uuid)['secret']['text']
      if _secret:
        account['secret'] = _secret
        accounts.append(account)
  print(json.dumps(accounts, indent=2))


if __name__ == '__main__':
  main()
[
  {
    "uuid": "c8d8a726-a7c2-4b13-98a4-15f9c3831ef4",
    "hash": "77518b39e620ac271bfc58639796160cb3984af0a3e5f4367230ad768855e8e7",
    "secret": "HYXP4Wj2c51+5RErPH29pfb0hmdnz/QZNNIxwH3dFi+5KO9n1dPWGXR6yCPB7Z4CeZ7cuMFZzXVfvqEtvvFlR2Tg5NOD6rk9azaZ"
  },
  {
    "uuid": "f79dd76f-2ce4-420f-bf46-f0ba82af04fb",
    "hash": "87bcb0554d72bd277ae6c2795b8e09e03c56ed4314352449c3d371b70cdc1ea8",
    "secret": "QEL9U16s9VK4mI5iRdTEBQFzw13s877sE0f4SedWhfq18XvWRW/gvi5xoCMh9zNQTiWu2AwQN8M1zLKpPEAh8z+9VSSDQ+j3Xl9fCqgRBfbPZc+G/7zZK5XE5koKkZxad6a5qa8="
  },
  {
    "uuid": "4d1713c1-ef9e-46b1-9fee-9ac57d4180b8",
    "hash": "e045171f3d3d93ee538b4673f7b5184bfd7d9eaa200f29f81ae1b7123a32ebca",
    "secret": "MM7Kh/WU5cbbxU/H+FGRA07teK5vJHctdSNe7X60rs2qtgG+t//T/WX4HmWz+q8Nhzg="
  }
]

Cassage de mot de passe

3 comptes parmis les uuid dans wordlist.txt existes, il faut maintenant casser leur hash avec un bruteforce. Comme indiqué dans la description, on part sur rockyou.txt :

from hashlib import sha256
import json
import requests

HOST = '35.242.231.98'
PORT = 30512
ACCOUNTS = [
  {
    "uuid": "c8d8a726-a7c2-4b13-98a4-15f9c3831ef4",
    "hash": "77518b39e620ac271bfc58639796160cb3984af0a3e5f4367230ad768855e8e7"
  },
  {
    "uuid": "f79dd76f-2ce4-420f-bf46-f0ba82af04fb",
    "hash": "87bcb0554d72bd277ae6c2795b8e09e03c56ed4314352449c3d371b70cdc1ea8"
  },
  {
    "uuid": "4d1713c1-ef9e-46b1-9fee-9ac57d4180b8",
    "hash": "e045171f3d3d93ee538b4673f7b5184bfd7d9eaa200f29f81ae1b7123a32ebca"
  }
]


def request(method: str, path: str, uuid: str):
  headers = {
    'X-MOBISEC': 'ef75826d9de13292593aa57f82a7763d',
    'Accept': 'application/json'
  }
  url = f'http://{HOST}:{PORT}{path}{uuid}'
  return requests.request(method=method, url=url, headers=headers).json()


def hashing(s: bytes) -> str:
  return sha256(b'LbhXabjVaCenpgvprFnygfNerHavdhrylTrarengrqSbeRirelCnffOhgVzGbbYnmlGbPbqrGung:)' + s).hexdigest()


def main():
  to_find = len(ACCOUNTS)
  found = 0
  with open('E:/Downloads/rockyou.txt', 'rb') as f:
    for password in f:
      if password == b'':
        break
      password = password.strip(b'\n')
      _hash = hashing(password)
      for account in ACCOUNTS:
        if account['hash'] == _hash:
          account['password'] = password.decode()
          found += 1
      if found == to_find:
        break
    print(json.dumps(ACCOUNTS, indent=2))


if __name__ == '__main__':
  main()
[
  {
    "uuid": "c8d8a726-a7c2-4b13-98a4-15f9c3831ef4",
    "hash": "77518b39e620ac271bfc58639796160cb3984af0a3e5f4367230ad768855e8e7",
    "secret": "HYXP4Wj2c51+5RErPH29pfb0hmdnz/QZNNIxwH3dFi+5KO9n1dPWGXR6yCPB7Z4CeZ7cuMFZzXVfvqEtvvFlR2Tg5NOD6rk9azaZ",
    "password": "86390627"
  },
  {
    "uuid": "f79dd76f-2ce4-420f-bf46-f0ba82af04fb",
    "hash": "87bcb0554d72bd277ae6c2795b8e09e03c56ed4314352449c3d371b70cdc1ea8",
    "secret": "QEL9U16s9VK4mI5iRdTEBQFzw13s877sE0f4SedWhfq18XvWRW/gvi5xoCMh9zNQTiWu2AwQN8M1zLKpPEAh8z+9VSSDQ+j3Xl9fCqgRBfbPZc+G/7zZK5XE5koKkZxad6a5qa8=",
    "password": "SHALLOWgrounds13"
  },
  {
    "uuid": "4d1713c1-ef9e-46b1-9fee-9ac57d4180b8",
    "hash": "e045171f3d3d93ee538b4673f7b5184bfd7d9eaa200f29f81ae1b7123a32ebca",
    "secret": "MM7Kh/WU5cbbxU/H+FGRA07teK5vJHctdSNe7X60rs2qtgG+t//T/WX4HmWz+q8Nhzg=",
    "password": "killerpink007"
  }
]

Récupération des secrets

Maintenant que l'on connaît les mots de passe, on peut déchiffrer les secrets ?

Eh bien non, il y a eu un GROS foirage dans le CTF et la façon dont sont stockés les secrets (et donc le flag) sur le serveur n'est pas la même que celle sur l'application.

Il faut utiliser PBKDF2 avec SHA1 (et pas SHA256) et ensuite, comme indiqué dans la description (changée 2 fois en 2j de CTF), le nonce, le tag et le ciphertext sont placé différemment.

from hashlib import sha256, pbkdf2_hmac
import json
from base64 import b64decode
from Crypto.Cipher import AES


ACCOUNTS = [
  {
    "uuid": "c8d8a726-a7c2-4b13-98a4-15f9c3831ef4",
    "hash": "77518b39e620ac271bfc58639796160cb3984af0a3e5f4367230ad768855e8e7",
    "secret": "HYXP4Wj2c51+5RErPH29pfb0hmdnz/QZNNIxwH3dFi+5KO9n1dPWGXR6yCPB7Z4CeZ7cuMFZzXVfvqEtvvFlR2Tg5NOD6rk9azaZ",
    "password": "86390627"
  },
  {
    "uuid": "f79dd76f-2ce4-420f-bf46-f0ba82af04fb",
    "hash": "87bcb0554d72bd277ae6c2795b8e09e03c56ed4314352449c3d371b70cdc1ea8",
    "secret": "QEL9U16s9VK4mI5iRdTEBQFzw13s877sE0f4SedWhfq18XvWRW/gvi5xoCMh9zNQTiWu2AwQN8M1zLKpPEAh8z+9VSSDQ+j3Xl9fCqgRBfbPZc+G/7zZK5XE5koKkZxad6a5qa8=",
    "password": "SHALLOWgrounds13"
  },
  {
    "uuid": "4d1713c1-ef9e-46b1-9fee-9ac57d4180b8",
    "hash": "e045171f3d3d93ee538b4673f7b5184bfd7d9eaa200f29f81ae1b7123a32ebca",
    "secret": "MM7Kh/WU5cbbxU/H+FGRA07teK5vJHctdSNe7X60rs2qtgG+t//T/WX4HmWz+q8Nhzg=",
    "password": "killerpink007"
  }
]


def decrypt(password: str, encrypted_data: bytes):
  nonce, tag, ciphertext = encrypted_data[:16], encrypted_data[16:32], encrypted_data[32:]
  key = pbkdf2_hmac(hash_name='sha1', password=password.encode(), salt=b'0123456789abcdef', iterations=100000, dklen=256//8)
  cipher = AES.new(key, AES.MODE_GCM, nonce)
  return cipher.decrypt_and_verify(ciphertext=ciphertext, received_mac_tag=tag).decode()


def main():
  for account in ACCOUNTS:
    account['text'] = decrypt(account['password'], b64decode(account['secret']))
  print(json.dumps(ACCOUNTS, indent=2))


if __name__ == '__main__':
  main()
[
  {
    "uuid": "c8d8a726-a7c2-4b13-98a4-15f9c3831ef4",
    "hash": "77518b39e620ac271bfc58639796160cb3984af0a3e5f4367230ad768855e8e7",
    "secret": "HYXP4Wj2c51+5RErPH29pfb0hmdnz/QZNNIxwH3dFi+5KO9n1dPWGXR6yCPB7Z4CeZ7cuMFZzXVfvqEtvvFlR2Tg5NOD6rk9azaZ",
    "password": "86390627",
    "text": "Secret cookie recipe: ... (in construction)"
  },
  {
    "uuid": "f79dd76f-2ce4-420f-bf46-f0ba82af04fb",
    "hash": "87bcb0554d72bd277ae6c2795b8e09e03c56ed4314352449c3d371b70cdc1ea8",
    "secret": "QEL9U16s9VK4mI5iRdTEBQFzw13s877sE0f4SedWhfq18XvWRW/gvi5xoCMh9zNQTiWu2AwQN8M1zLKpPEAh8z+9VSSDQ+j3Xl9fCqgRBfbPZc+G/7zZK5XE5koKkZxad6a5qa8=",
    "password": "SHALLOWgrounds13",
    "text": "CTF{77cd55d22ef0d516a45ed0e238fbc5dbc4c93b0824047ea3e0a0509a5a9735ac}"
  },
  {
    "uuid": "4d1713c1-ef9e-46b1-9fee-9ac57d4180b8",
    "hash": "e045171f3d3d93ee538b4673f7b5184bfd7d9eaa200f29f81ae1b7123a32ebca",
    "secret": "MM7Kh/WU5cbbxU/H+FGRA07teK5vJHctdSNe7X60rs2qtgG+t//T/WX4HmWz+q8Nhzg=",
    "password": "killerpink007",
    "text": "I'm using Arch btw"
  }
]

A noter le "I'm using Arch btw" pour un challenge avec autant de bug, ça fait sourire

🚩
📱
1MB
mobisec.zip
archive