← Back to Writeups
CUSTOMEasyMisc

Pechatnaya Mashinka

XESXOR9/2/20263 min read
#misc#custom#easy#pcap-analysis-with-tshark#usb-hid-keyboard-traffic-analy#usb-scan-code-decoding#linux

Pechatnaya Mashinka

Platform: hackerlab | Category: Misc | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-25 | Status: Solved Techniques: PCAP analysis with tshark, USB HID keyboard traffic analysis, USB scan code decoding

Summary

Task: Analyze a strange dump file. Solution: Extract USB HID keyboard traffic from PCAP and decode scan codes to recover typed text containing the flag.

Pechatnaya Mashinka - Hackerlab

Description

К нам в руки попал какой-то странный дамп. Поможешь разобраться?

The task name "Печатная машинка" (Typewriter) hints at keyboard input.

Analysis

1. File Identification

bash
file task.pcap
# task.pcap: pcap capture file, microsecond ts (little-endian) - version 2.4 (USB with USBPcap header, capture length 65535)

This is a USB capture file - a USB traffic dump.

2. Extracting USB HID Data

bash
tshark -r task.pcap -T fields -e usb.capdata > usb_data.txt

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

We get data like:

0000090000000000
0000000000000000
00000f0000000000
...
0100060000000000
0100120000000000

3. USB HID Keyboard Report Structure

8-byte HID keyboard report:

  • Byte 0: Modifier keys (Shift, Ctrl, Alt, etc.)
  • Byte 1: Reserved (always 0)
  • Byte 2: Keycode 1
  • Bytes 3-7: Additional keycodes (for key rollover)

Modifier byte:

  • 0x01 = Left Ctrl (but in this capture it's used as Shift!)
  • 0x02 = Left Shift (standard)
  • 0x20 = Right Shift

4. Key Observation

In this capture, modifier byte 0x01 is used as Shift (non-standard). This is evident from context - uppercase letters in "CODEBY{" have modifier 0x01. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

python
#!/usr/bin/env python3
"""
USB HID Keyboard decoder for CTF task "Печатная машинка"
"""

# USB HID Keyboard scan codes to characters
# Reference: https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf

KEY_CODES = {
    0x04: ('a', 'A'),
    0x05: ('b', 'B'),
    0x06: ('c', 'C'),
    0x07: ('d', 'D'),
    0x08: ('e', 'E'),
    0x09: ('f', 'F'),
    0x0a: ('g', 'G'),
    0x0b: ('h', 'H'),
    0x0c: ('i', 'I'),
    0x0d: ('j', 'J'),
    0x0e: ('k', 'K'),
    0x0f: ('l', 'L'),
    0x10: ('m', 'M'),
    0x11: ('n', 'N'),
    0x12: ('o', 'O'),
    0x13: ('p', 'P'),
    0x14: ('q', 'Q'),
    0x15: ('r', 'R'),
    0x16: ('s', 'S'),
    0x17: ('t', 'T'),
    0x18: ('u', 'U'),
    0x19: ('v', 'V'),
    0x1a: ('w', 'W'),
    0x1b: ('x', 'X'),
    0x1c: ('y', 'Y'),
    0x1d: ('z', 'Z'),
    0x1e: ('1', '!'),
    0x1f: ('2', '@'),
    0x20: ('3', '#'),
    0x21: ('4', '$'),
    0x22: ('5', '%'),
    0x23: ('6', '^'),
    0x24: ('7', '&'),
    0x25: ('8', '*'),
    0x26: ('9', '('),
    0x27: ('0', ')'),
    0x28: ('\n', '\n'),  # Enter
    0x29: ('[ESC]', '[ESC]'),
    0x2a: ('[BACKSPACE]', '[BACKSPACE]'),
    0x2b: ('\t', '\t'),
    0x2c: (' ', ' '),  # Space
    0x2d: ('-', '_'),
    0x2e: ('=', '+'),
    0x2f: ('[', '{'),
    0x30: (']', '}'),
    0x31: ('\\', '|'),
    0x33: (';', ':'),
    0x34: ("'", '"'),
    0x35: ('`', '~'),
    0x36: (',', '<'),
    0x37: ('.', '>'),
    0x38: ('/', '?'),
}
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

def decode_usb_keyboard(data_file):
    result = []
    
    with open(data_file, 'r') as f:
        for line in f:
            line = line.strip()
            if not line or len(line) < 16:
                continue
            
            # Parse hex data
            try:
                data = bytes.fromhex(line)
            except:
                continue
            
            if len(data) < 3:
                continue
            
            modifier = data[0]
            keycode = data[2]
            
            # Skip if no key pressed (key release events)
            if keycode == 0:
                continue
            
            # Check if Shift is pressed
            # In this capture: 0x01 seems to act as Shift (non-standard)
            # Standard: 0x02 = Left Shift, 0x20 = Right Shift
            shift = (modifier & 0x23) != 0  # Include 0x01 as shift
            
            if keycode in KEY_CODES:
                char = KEY_CODES[keycode][1 if shift else 0]
                result.append(char)
            else:
                result.append(f'[0x{keycode:02x}]')
    
    return ''.join(result)
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

if __name__ == '__main__':
    decoded = decode_usb_keyboard('usb_data.txt')
    print("Decoded keyboard input:")
    print(decoded)

Execution

bash
python3 solve.py
# Decoded keyboard input:
# flag = CODEBY{REDACTED}

Useful Commands

bash
# Extract USB data via tshark
tshark -r task.pcap -T fields -e usb.capdata

# Alternatively via Wireshark filter
usb.transfer_type == 0x01 && usb.data_len == 8

References

  • USB HID Usage Tables
  • USB Keyboard Scan Codes ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍