← Back to Writeups
CUSTOMMediumForensics

Новый сотрудник 2 (New Employee 2)

XESXOR9/2/20265 min read
#forensics#custom#medium#mouse_movement_parsing#signed_byte_conversion#trajectory_visualization#usb_hid_decoding#linux

Новый сотрудник 2 (New Employee 2)

Platform: hackerlab | Category: Forensics | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-01-06 | Status: Solved Techniques: mouse_movement_parsing, signed_byte_conversion, trajectory_visualization, usb_hid_decoding

Summary

Task: Analyze USB traffic pcapng to find what an employee was doing. Solution: Identify USB HID mouse protocol, extract movement deltas, and visualize the trajectory to reveal the flag drawn with the mouse.

Новый сотрудник 2 (New Employee 2) - Hackerlab

Description

Вроде бы сейчас дефицит IT-кадров? Мы взяли к себе ещё одного нового сотрудника и нам снова нужно проверить, что он делает в рабочее время, ты сможешь нам помочь?

(Translation: "Seems like there's an IT talent shortage? We hired another new employee and we need to check what they're doing during work hours again, can you help us?")

Files: new_employee_2.zip -> traffic.pcapng

Analysis

Step 1: Examining the pcapng

Unpack the archive and analyze its contents: ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

bash
unzip new_employee_2.zip
file traffic.pcapng

Check the traffic type:

bash
tshark -r traffic.pcapng -T fields -e frame.protocols | sort -u

We discover that this is USB traffic, not network traffic!

Step 2: Device Identification

bash
tshark -r traffic.pcapng -Y "usb.bInterfaceClass == 0x03" -T fields -e usb.bInterfaceProtocol | head
  • bInterfaceClass = 0x03 - HID (Human Interface Device)
  • bInterfaceProtocol = 0x02 - Mouse (0x01 = Keyboard, 0x02 = Mouse)

This is a continuation of the "Новый сотрудник" (New Employee) task, but now instead of a keyboard - it's a mouse. ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Step 3: Extracting HID Data

bash
tshark -r traffic.pcapng -Y "usb.transfer_type == 0x01" -T fields -e usbhid.data > mouse_data.txt

USB mouse data format (8 bytes):

Byte 0: Button state (bit 0 = left, bit 1 = right, bit 2 = middle)
Byte 1: X delta (signed, -128 to 127)
Byte 2: Y delta (signed, -128 to 127)
Byte 3: Wheel delta (signed)
Bytes 4-7: Reserved/Extended data

Step 4: Understanding the Format

X and Y deltas are signed bytes:

  • Values 0-127: positive offset
  • Values 128-255: negative offset (need to subtract 256) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Solution

Script for Mouse Trajectory Visualization

python
#!/usr/bin/env python3
"""
USB Mouse HID Data Visualizer
Parses mouse movement data and draws the trajectory
"""

from PIL import Image, ImageDraw

def parse_signed_byte(value):
    """Convert unsigned byte to signed (-128 to 127)"""
    return value if value <= 127 else value - 256

def main():
    # Read extracted HID data
    with open('mouse_data.txt', 'r') as f:
        lines = [line.strip() for line in f if line.strip()]
    
    # Starting position (center of canvas)
    x, y = 1000, 500
    
    # Track all positions and click positions
    positions = [(x, y)]
    clicks = []
    
    for line in lines:
        try:
            data = bytes.fromhex(line.replace(':', ''))
            if len(data) < 3:
                continue
            
            # Parse mouse data
            button = data[0]
            dx = parse_signed_byte(data[1])
            dy = parse_signed_byte(data[2])
            
            # Update position
            x += dx
            y += dy
            positions.append((x, y))
            
            # Track left clicks (button bit 0)
            if button & 0x01:
                clicks.append((x, y))
                
        except (ValueError, IndexError):
            continue
    
    # Calculate bounding box
    min_x = min(p[0] for p in positions)
    max_x = max(p[0] for p in positions)
    min_y = min(p[1] for p in positions)
    max_y = max(p[1] for p in positions)
    
    # Create image with padding
    padding = 50
    width = max_x - min_x + 2 * padding
    height = max_y - min_y + 2 * padding
    
    img = Image.new('RGB', (width, height), 'white')
    draw = ImageDraw.Draw(img)
    
    # Normalize positions
    normalized = [(p[0] - min_x + padding, p[1] - min_y + padding) for p in positions]
    normalized_clicks = [(c[0] - min_x + padding, c[1] - min_y + padding) for c in clicks]
    
    # Draw trajectory line
    if len(normalized) > 1:
        draw.line(normalized, fill='black', width=2)
    
    # Mark click positions in red
    for cx, cy in normalized_clicks:
        draw.ellipse([cx-3, cy-3, cx+3, cy+3], fill='red')
    
    # Save result
    img.save('mouse_trajectory.png')
    print(f"Saved: mouse_trajectory.png ({width}x{height})")
    print(f"Total positions: {len(positions)}")
    print(f"Total clicks: {len(clicks)}")
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

if __name__ == '__main__':
    main()

Alternative Script (with Button Press Tracking)

python
#!/usr/bin/env python3
"""
Alternative: Only draw when button is pressed (like drawing with pen)
"""

from PIL import Image, ImageDraw

def parse_signed_byte(value):
    return value if value <= 127 else value - 256

with open('mouse_data.txt', 'r') as f:
    lines = [line.strip() for line in f if line.strip()]

x, y = 1000, 500
drawing_segments = []
current_segment = []
was_pressed = False

for line in lines:
    try:
        data = bytes.fromhex(line.replace(':', ''))
        if len(data) < 3:
            continue
        
        button = data[0]
        dx = parse_signed_byte(data[1])
        dy = parse_signed_byte(data[2])
        
        x += dx
        y += dy
        
        is_pressed = bool(button & 0x01)
        
        if is_pressed:
            current_segment.append((x, y))
        elif was_pressed and current_segment:
            drawing_segments.append(current_segment)
            current_segment = []
        
        was_pressed = is_pressed
        
    except (ValueError, IndexError):
        continue
‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

if current_segment:
    drawing_segments.append(current_segment)

# Find bounds
all_points = [p for seg in drawing_segments for p in seg]
if all_points:
    min_x = min(p[0] for p in all_points)
    max_x = max(p[0] for p in all_points)
    min_y = min(p[1] for p in all_points)
    max_y = max(p[1] for p in all_points)
    
    padding = 50
    width = max_x - min_x + 2 * padding
    height = max_y - min_y + 2 * padding
    
    img = Image.new('RGB', (width, height), 'white')
    draw = ImageDraw.Draw(img)
    
    for segment in drawing_segments:
        normalized = [(p[0] - min_x + padding, p[1] - min_y + padding) for p in segment]
        if len(normalized) > 1:
            draw.line(normalized, fill='black', width=2)
    
    img.save('mouse_drawing.png')
    print(f"Saved: mouse_drawing.png")

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

Result

The generated image shows what the employee drew with the mouse:

  • Flag text: CODEBY{REDACTED}
  • Heart symbol (additional drawing)

USB HID Mouse Data Format Reference

ByteDescriptionValues
0Button stateBit 0: Left, Bit 1: Right, Bit 2: Middle
1X deltaSigned: -128 to +127
2Y deltaSigned: -128 to +127
3Wheel deltaSigned: scroll up/down
4-7ExtendedReserved or device-specific

Related Tasks

  • Новый сотрудник (New Employee) - same series, but with USB keyboard
  • Both tasks use USB HID analysis, but different protocols (keyboard vs mouse) ‍​‌‌​​​​‌​‌‌​​‌‌​​‌‌​​‌‌​​‌‌​​‌​​​​‌‌​​​​​‌‌​​‌‌​​‌‌​​‌​‌​‌‌​​‌​‌‍

Useful tshark Commands

bash
# Show all USB devices
tshark -r traffic.pcapng -Y "usb.bDescriptorType == 1" -T fields -e usb.idVendor -e usb.idProduct

# Extract only HID data
tshark -r traffic.pcapng -Y "usbhid.data" -T fields -e usbhid.data

# Filter by transfer type (INTERRUPT = 0x01)
tshark -r traffic.pcapng -Y "usb.transfer_type == 0x01" -T fields -e usbhid.data

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