Writeups
  • ℹ️Infos
  • 🗓️2021
    • DvCTF (to join DaVinciCode)
      • Crypto
        • Baby RSA
        • Ressaye
        • Unbreakable encryption
      • Forensics
        • Broken Portrait
        • Russian Dolls
        • Sus USB
      • Misc
        • Jus de Flag
        • Welcome
      • OSINT
        • Absolutely Nuts
      • Progra
        • Snoop's Mission
      • Reverse
        • Baby Reverse
        • Basic Cracking
        • Code Pyn
      • Steganography
        • Colorful Code
        • Hurt Your Eyes
        • Orchestra of Flags
        • Tyger
      • Web
        • Have I Been Pwned
        • What's Up ?
  • 🗓️2022
    • DvCTF 2022
      • Crypto
        • Cwryptographic Owacle
        • Secure Or Not Secure
        • small weiner
      • Forensics
        • Very Bad Script
      • Misc
        • Data Leak
        • Going postal
        • The Hacker Man
      • OSINT
        • Elon Musk
        • Monkeey
        • Painting Spot
        • Welcome to the DaVinciCTF!
      • Pentest
        • DaVinci's Playlist : Part 1
        • DaVinci's Playlist : Part 2.5
        • DaVinci's Playlist : Part 2
      • Programming
        • Heaven's Gate
        • Sudoku
        • TicTacToe
      • Reverse
        • CryptoVault
        • Mine Game
        • Obfuscated
        • Peripheral Interface Controller XVI
      • Steganography
        • ICMP
        • The Arts of Details
        • Treasure
      • Warmup
        • EBG13
        • FrenchFlag
        • MP3
        • QmFzZTY0
        • RSA
        • Welcome
      • Web
        • CyberStreak v1.0
        • 🎵
    • picoCTF 2022
      • Challs WU
    • @HackDay - Qualifications
      • Crypto
        • Francis Bacon
        • Francs Maçons
        • Rotate-me!
        • Un message codé ?
      • Forensics
        • bad_timing_for_reversing
      • Hardware
        • Cubik'cipher
        • WebSDR
      • Reverse
        • Calling Conventions
        • Memory Investigation
      • Steganography
        • I can make pictures
        • J'ai perdu le flag :(
        • Pokémons
        • Un coup de maître
        • Un logo cachotier
      • Web
        • GIT!
        • Part. 1 - Uploads
        • Part. 2 - Old md5
        • Part. 3 - sudo python
    • 404CTF
      • Crypto
        • Un simple oracle [1/2]
        • Un simple oracle [2/2]
      • Misc
        • Je suis une théière
        • Pierre-papier-Hallebarde
        • GoGOLFplex
      • OSINT
        • À l'aube d'un échange
        • Collaborateur suspect
        • Equipement désuet
      • Reverse
        • Mot de passe ?
      • Steganography
        • La plume à la main
        • PNG : Un logo obèse [1/4]
        • PNG : Drôles de chimères [2/4]
        • Toujours obèse [3/4]
      • Web
        • Fiché JS
        • Le braquage
        • Du gâteau
        • En construction !
    • Operation Kernel
      • Crypto
        • Scytale
      • Forensics
        • Research Paper
        • Excel Confidential
      • Reverse
        • CryptoLocker
        • What_If_CryptoLocker
      • Social Engineering
        • Pour vivre secure vivons caché
        • Pour vivre secure vivons caché Part 2
      • Stegano
        • AudioSpectre
        • Datacenter
        • Takazume
      • WEB
        • Research paper blog
        • SQL Project 1
        • SQL Project 2
        • SQL Project 3
        • Tenue de soirée requise
  • 🗓️2023
    • 404CTF 2023
      • Résultats
      • Analyse forensique
        • Pêche au livre
        • Le Mystère du roman d'amour
        • Les Mystères du cluster de la Comtesse de Ségur [1/2]
        • Lettres volatiles
        • Note de bas de page
      • Cloud
        • Le Sot
        • Le Cluster de Madame Bovary
        • Harpagon et le magot
        • Les nuages menaçants 1/3
        • Les nuages menaçants 2/3
      • Cryptanalyse
        • Recette
        • ASCON Marchombre
      • Divers
        • Bienvenue
        • Exemple de connexion à distance
        • Discord
        • À vos plumes !
      • Exploitation de binaires
        • Je veux la lune !
      • Programmation
        • L'Inondation
        • Des mots, des mots, des mots
      • Radio-Fréquence
        • Navi
        • Avez-vous vu les cascades du hérisson ?
        • Le Plombier du câble
        • Ballistic Missile Submarine
      • Renseignement en sources ouvertes
        • Le Tour de France
        • Les OSINTables [1/3]
        • Un vol ?
        • L'âme d'un poète et le coeur d'une femme [1/4]
        • L'âme d'un poète et le coeur d'une femme [2/4]
        • L'âme d'un poète et le coeur d'une femme [3/4]
        • L'âme d'un poète et le coeur d'une femme [4/4]
      • Rétro Ingénierie
        • Le Divin Crackme
        • L'Inspiration en images
      • Sécurité Matérielle
        • Un courrier suspect
        • Un réveil difficile
      • Stéganographie
        • Odobenus Rosmarus
        • L'Œuvre
        • Les Félicitations
        • En Profondeur
        • Le Rouge et le vert, avec un soupçon de bleu
      • Web
        • Le Loup et le renard
        • L'Académie du détail
        • La Vie Française
        • Fuite en 1791
        • L'Épistolaire moderne
        • Chanson d'Inde
      • Web3
        • Art
        • L'Antiquaire, tête en l'air
  • 🗓️2025
    • 404CTF 2025
      • Résultats
      • Algorithmique Quantique
        • Machinerie quantique
        • Grover (1/2)
        • Grover (2/2)
      • Analyse forensique
        • USB 51
        • Forensic et Mat [1/2]
        • Apprenti Carver [1/2]
        • Dockerflag
        • Forensic et Mat [2/2]
        • Apprenti Carver [2/2]
        • Tape ton MDP
        • Toortik Triflexation [1/2]
        • Toortik Triflexation [2/2]
      • Cryptanalyse
        • Message lointain
        • Entretien galactique
        • R1R2
        • Saturn Cipher
        • Planètes anormales
        • Spacemark
        • You spin me round
        • Dérive dans l'espace
        • Lunette cosmico galactique
        • Jupiter Cipher
        • Courbe de Lancement
        • More Space
      • Divers
        • Bienvenue
        • Pix2Num
        • Politique de confidentialité
        • Space Traveller
        • Satellisation
        • Étoile binaire [2/2]
      • Exploitation de binaires
        • Gorfou en danger [1/3]
        • Gorfou en danger [2/3]
        • Gorfou en danger [3/3]
        • Spaaaaaaace
        • KerberINT Space Program
        • 22 bytes pour sauver l'univers
        • Bounty Machine
        • Space Odyssey
        • Solaris
        • Cosmic-Base
        • Kalaxy
        • Bokit
      • Intelligence Artificielle
        • Gorfoustral (1/3)
        • Gorfoustral (2/3)
        • Gorfoustral (3/3)
        • Du tatouage
      • Renseignement en sources ouvertes
        • L'addition est salée
        • Une mission inconnue
        • Earth Attack (0/2)
        • Un satellite qui vaut de l'or
        • Un peu de vacances
        • La ville en rose
        • Earth Attack (1/2)
        • La tête dans les étoiles
        • En eaux sombres
        • Earth Attack (2/2)
        • DPOsint
      • Réaliste
        • The LDAP Chronicles
        • Houston, we have a problem
        • Named Resolve
        • The AD Guardians
        • The GPO Mission
        • Ghost Membership
      • Rétro-Ingénierie
        • Cbizarre [1/2]
        • Cbizarre [2/2]
        • Reversconstrictor
        • 3x3cut3_m3
        • Inscription
        • Étoile binaire [1/2]
        • RFC 9452 bis: IP over Rockets with Quality of Service
      • Sécurité matérielle
        • Trop d'IQ
        • Space Radio
        • R16D4
        • Comment est votre température ?
        • Code Radiospatial n°1
        • Unidentified Serial Bus [1/2]
        • Unidentified Serial Bus [2/2]
      • Sécurité Web
        • Cheese Chess
        • Rainbow Rocket
        • Fire Server
        • Sideral Noise
        • Space Fleet Command
Powered by GitBook
On this page

Was this helpful?

  1. 2025
  2. 404CTF 2025
  3. Analyse forensique

Tape ton MDP

PreviousApprenti Carver [2/2]NextToortik Triflexation [1/2]

Last updated 4 days ago

Was this helpful?

Catégorie: Analyse forensique - Difficulté: Moyen

Description:

Solution:

Ici nous avons une capture réseau qui exfiltre des données vers l'extérieur. À la vue du titre du chall ainsi que sa description, il s'agit d'un keylogger, nous allons donc devoir reconstituer ce que la personne a tapé au clavier.

Pour ce faire, après analyse manuelle (et avec une IA 🙃), nous trouvons les données intéressantes se trouvent à chaque requête HTTP vers /upload :

Maintenant pour déchiffrer tout cela, nous pouvons utiliser le script suivant :

import base64
import struct
import re

# AZERTY mapping based on standard US keycodes
AZERTY_LOWER = {
    1: 'ESC', 2: '&', 3: 'é', 4: '"', 5: "'", 6: '(', 7: '-', 8: 'è', 9: '_', 10: 'ç', 11: 'à',
    12: ')', 13: '=', 14: 'BACKSPACE', 15: 'TAB',
    16: 'a', 17: 'z', 18: 'e', 19: 'r', 20: 't', 21: 'y', 22: 'u', 23: 'i', 24: 'o', 25: 'p',
    26: '^', 27: '$', 28: '\n',  # KEY_ENTER
    29: 'L_CTRL', 30: 'q', 31: 's', 32: 'd', 33: 'f', 34: 'g', 35: 'h', 36: 'j', 37: 'k', 38: 'l',
    39: 'm', 40: 'ù', 41: '²', # Grave accent key (typically left of '1' on US layout, maps to '²')
    42: 'L_SHIFT',
    43: '*', # US backslash key, often '*' on AZERTY. Can also be '<' (keycode 86 for that usually)
    44: 'w', 45: 'x', 46: 'c', 47: 'v', 48: 'b', 49: 'n', 50: ',',
    51: ';', 52: ':', 53: '!', 54: 'R_SHIFT', 55: '*', # Numpad *
    56: 'L_ALT', 57: ' ', 58: 'CAPS_LOCK',
    59: 'F1', 60: 'F2', 61: 'F3', 62: 'F4', 63: 'F5', 64: 'F6', 65: 'F7', 66: 'F8', 67: 'F9', 68: 'F10',
    69: 'NUMLOCK', 70: 'SCROLLLOCK',
    71: '7', 72: '8', 73: '9', # Numpad
    74: '-', # Numpad -
    75: '4', 76: '5', 77: '6', # Numpad
    78: '+', # Numpad +
    79: '1', 80: '2', 81: '3', # Numpad
    82: '0', # Numpad 0
    83: '.', # Numpad .
    86: '<', # Often the key for < > on AZERTY
    96: '\n', # Numpad Enter
    98: '/', # Numpad /
}

AZERTY_UPPER = {
    1: 'ESC', 2: '1', 3: '2', 4: '3', 5: '4', 6: '5', 7: '6', 8: '7', 9: '8', 10: '9', 11: '0',
    12: '°', 13: '+', 14: 'BACKSPACE', 15: 'TAB',
    16: 'A', 17: 'Z', 18: 'E', 19: 'R', 20: 'T', 21: 'Y', 22: 'U', 23: 'I', 24: 'O', 25: 'P',
    26: '¨', 27: '£', 28: '\n', # KEY_ENTER
    29: 'L_CTRL', 30: 'Q', 31: 'S', 32: 'D', 33: 'F', 34: 'G', 35: 'H', 36: 'J', 37: 'K', 38: 'L',
    39: 'M', 40: '%', 41: '', # Shift+² is often nothing or same as unshifted ²
    42: 'L_SHIFT',
    43: 'µ', # If unshifted is '*'
    44: 'W', 45: 'X', 46: 'C', 47: 'V', 48: 'B', 49: 'N', 50: '?',
    51: '.', 52: '/', 53: '§', 54: 'R_SHIFT', 55: '*', # Numpad *
    56: 'L_ALT', 57: ' ', 58: 'CAPS_LOCK',
    59: 'F1', 60: 'F2', 61: 'F3', 62: 'F4', 63: 'F5', 64: 'F6', 65: 'F7', 66: 'F8', 67: 'F9', 68: 'F10',
    69: 'NUMLOCK', 70: 'SCROLLLOCK',
    71: '7', 72: '8', 73: '9', # Numpad
    74: '-', # Numpad -
    75: '4', 76: '5', 77: '6', # Numpad
    78: '+', # Numpad +
    79: '1', 80: '2', 81: '3', # Numpad
    82: '0', # Numpad 0
    83: '.', # Numpad .
    86: '>', # Often the key for < > on AZERTY
    96: '\n', # Numpad Enter
    98: '/', # Numpad /
}

EV_KEY = 0x01
KEY_LEFTSHIFT = 42
KEY_RIGHTSHIFT = 54

def solve():
    collected_raw_tokens = []
    try:
        with open("http_data.txt", "r") as f:
            for line in f:
                line_stripped = line.strip()
                if line_stripped:
                    # Split by comma, but also handle cases where base64 strings might be concatenated
                    # by multipart boundaries if not perfectly clean before.
                    # The previous version's split was likely fine, this is just to be robust.
                    parts = line_stripped.split(',')
                    for part in parts:
                        # Remove potential multipart boundary remnants if any, though unlikely here
                        # as tshark extracts http.file_data which should be cleaner.
                        if '--------------------------' in part:
                            sub_parts = re.split(r"--------------------------[a-f0-9]+(?:--)?\\r\\n", part)
                            for sp in sub_parts:
                                if sp.strip(): collected_raw_tokens.append(sp.strip())
                        else:
                            if part.strip(): collected_raw_tokens.append(part.strip())

    except FileNotFoundError:
        print("Error: http_data.txt not found.")
        return

    if not collected_raw_tokens:
        print("No raw tokens extracted from http_data.txt.")
        return

    all_data_tokens = []
    for token_from_file in collected_raw_tokens:
        token = token_from_file.strip()
        if not token:
            continue

        processed_b64_part = ""
        # Handle the "bGxISEk=" prefix if present
        if token.startswith("bGxISEk=") and len(token) > 8:
            potential_part = token[8:]
            if len(potential_part) == 32:
                processed_b64_part = potential_part
        elif len(token) == 32:
            processed_b64_part = token
        
        if processed_b64_part:
            try:
                # Validate base64 characters and padding
                if not re.fullmatch(r'[A-Za-z0-9+/]*={0,2}', processed_b64_part):
                    continue
                base64.b64decode(processed_b64_part) # Test decode
                all_data_tokens.append(processed_b64_part)
            except Exception:
                pass # Invalid base64

    if not all_data_tokens:
        print("No valid 32-character Base64 data tokens found after filtering and validation.")
        return

    password_chars = []
    shift_pressed = False

    for b64_event_data in all_data_tokens:
        try:
            decoded_data = base64.b64decode(b64_event_data)
            if len(decoded_data) != 24: # sizeof(struct input_event) typically 24 bytes
                continue
            
            # struct input_event: timeval (long long, long long), type (ushort), code (ushort), value (uint)
            # Format: <QQHHI (little-endian, 2x unsigned long long, 2x unsigned short, unsigned int)
            _, _, type_val, code_val, val_val = struct.unpack("<QQHHI", decoded_data)

            if type_val == EV_KEY:
                if code_val == KEY_LEFTSHIFT or code_val == KEY_RIGHTSHIFT:
                    if val_val == 1: # Press
                        shift_pressed = True
                    elif val_val == 0: # Release
                        shift_pressed = False
                elif val_val == 1: # Key press (value=0 is release, value=2 is repeat)
                    char_to_add = None
                    current_map = AZERTY_UPPER if shift_pressed else AZERTY_LOWER
                    
                    char_to_add = current_map.get(code_val)
                    
                    # Fallback for keys that might not be in UPPER map but are in LOWER (e.g. space, enter)
                    if shift_pressed and char_to_add is None and code_val in AZERTY_LOWER:
                         #This case is tricky: if a key like SPACE is pressed with SHIFT, it's still SPACE.
                         #However, for letters, it's different. The current_map logic should handle most cases.
                         #Only if AZERTY_UPPER explicitly misses an entry that AZERTY_LOWER has, this might be useful.
                         pass # char_to_add = AZERTY_LOWER.get(code_val) - this might be wrong for letters.

                    if char_to_add:
                        if char_to_add == 'BACKSPACE':
                            if password_chars:
                                password_chars.pop()
                        # Filter out non-printable control key names unless they are part of the password (e.g. \n)
                        elif char_to_add not in ['L_SHIFT', 'R_SHIFT', 'L_CTRL', 'CAPS_LOCK', 'ESC', 'L_ALT', 'TAB',
                                                 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10',
                                                 'NUMLOCK', 'SCROLLLOCK']:
                            password_chars.append(char_to_add)
        except Exception as e:
            # print(f"Error processing token {b64_event_data}: {e}") # For debugging
            continue
            
    final_password = "".join(password_chars)
    if final_password:
        # The user expects the flag in 404CTF{...} format. 
        # We will print the raw output, and then manually check it.
        print(final_password)
    else:
        print("Could not reconstruct password from events with AZERTY mapping.")

if __name__ == "__main__":
    solve()

Ce script va donc prendre toutes les données exfiltrées et les déchiffrer étape par étape. Cela nous donne donc le résultat suivant :

Nous avons donc le flag affiché, il suffit simplement de lui refaire une petite beauté et tout sera bon :) S'il y a ' et = c'est du au fait que notre script ne prenne pas en compte la touche Alt-Gr afin de faire les accolades {}

🚩FLAG

404CTF{k3yl0gg3r_3xf1ltr4t10n}

🗓️
45KB
http_upload_data.txt
11MB
tape_ton_mdp.pcapng