2025 SWPU-NSSCTF 秋季招新入门训练赛(RE方向)

闲着没事,刚好看见NSS上有比赛,就去做做,感觉有些吃力做的,可能AI太宠我了,或者最近取证做多了,现在做的有点呛。

NSSCTF2025入门题目-Xor

ida看

输入的字符和7A做异或,后与enc_0的内容进行对比

对enc_0的内容进行提取,丢厨子里就好

NSSCTF2025入门题目-Base64

直接ida看

找到密文,然后在字符串中找到码表

丢个厨子就好

NSSCTF2025入门题目-Rc4

也是直接看

v3就是RC4的密匙,密文放在enc_0中

数据提取之后直接喂给厨子就行

NSSCTF2025入门题目-UPX

查壳

直接用upx脱壳即可

查看反编译,主要是异或之后和v6进行比较,看栈的话发现v5和v6相邻,那么v6读取为负数的时候会读取到v5,将v5和v6的值按小端序拆成一共20个字节,因为v6后面添加的部分会把v6最后一个字节给覆盖掉,所以一开始的只取7个字节,这样就是完整的19字节

v5 = 0xE013C2E39292934
v6_qword = 0xF25091325091312
v6_dword = 117574159
v5_bytes = v5.to_bytes(8, byteorder='little')
v6_q_truncated = v6_qword & 0xFFFFFFFFFFFFFF
v6_q_bytes = v6_q_truncated.to_bytes(7, byteorder='little') 
v6_d_bytes = v6_dword.to_bytes(4, byteorder='little')
flag1 = [chr(b ^ 0x7A) for b in v5_bytes]
flag2 = [chr(b ^ 0x7A) for b in v6_q_bytes] 
flag3 = [chr(b ^ 0x7A) for b in v6_d_bytes]
flag = ''.join(flag1 + flag2 + flag3)
print(flag)

NSSCTF2025入门题目-ida的使用

直接看找到第一段NSSCTF{

查看字符串找到第二段IDA_1s_4_VeRy_Impo

根据提示找到第三段rTan_t0ol_iN_

第四段提示,找到输出的代码,那就进行动调

在print_nothing处下断点,将rip的地址改为print_flag4

运行可得到第四段rever5e_en8ine3ring}

然后拼接起来就可以了

NSSCTF2025入门题目-认识asm

就是给你看汇编,核心就是flag [i] = flag [i] ^ (flag [i+1] + 1),根据这个写逆向的脚本

def decrypt(enc_flag):
    flag = list(enc_flag)
    length = len(flag)
    for i in range(length - 3, -1, -1):
        flag[i] ^= (flag[i + 1] + 1)
    return bytes(flag)
if __name__ == "__main__":
    enc_flag = bytes([0x1a, 0x7, 0x17, 0x16, 0x13, 0x3a, 0x39, 0x15, 0x1d, 0x2d, 0x35, 0x1d, 0x13, 0x3b, 0x10, 0x4,0x11, 0x9, 0xb, 0xc, 0xc, 0x2a, 0x4, 0xf, 0x1c, 0x28, 0x6, 0xc, 0x12, 0x8, 0x6, 0x7e, 0x7d])
    decrypted_flag = decrypt(enc_flag)
    print(decrypted_flag.decode('utf-8', errors='replace'))

NSSCTF2025入门题目-Z3

查看伪代码

在cul中找到z3的函数

这个比较小,不用z3也行,但是都这么说了,还是写个z3的脚本

from z3 import *
a=[Int('a[%d]'%i) for i in range(10)]
s=Solver()
s.add(2*a[7] + 8*a[6] + 8*a[5] + 2*a[4] + 4*a[3] + 5*a[1] + 2*a[0] + 6*a[2] + a[8] + 5*a[9] == 3976)
s.add(a[5] + 9*a[3] + 7*a[2] + 5*a[1] + 3*a[0] + 7*a[4] + 4*a[6] + 6*a[7] + 8*a[8] + 5*a[9] == 5265)
s.add(7*a[8] + 2*a[6] + 6*a[4] + 7*a[3] + 7*a[2] + 3*a[1] + 8*a[0] + 5*a[5] + 4*a[7] + 9*a[9] == 5284)
s.add(7*a[6] + 5*a[5] + 6*a[4] + 3*a[3] + 9*a[0] + 6*a[1] + 4*a[2] + 9*a[7] + 8*a[8] + 7*a[9] == 5925)
s.add(7*a[8] + 8*a[6] + 6*a[4] + a[2] + 4*a[1] + 3*a[0] + 2*a[3] + 5*a[5] + 2*a[7] + 3*a[9] == 4048)
s.add(3*a[8] + 9*a[7] + 7*a[6] + 4*a[4] + 4*a[3] + 5*a[0] + 8*a[1] + 6*a[2] + 4*a[5] + 7*a[9] == 5072)
s.add(5*a[7] + 2*a[3] + 2*(a[0] + a[1]) + 3*a[2] + a[4] + 7*a[5] + 2*a[6] + 3*a[8] + 2*a[9] == 2813)
s.add(3*a[8] + 5*a[7] + 7*a[6] + 3*a[5] + 7*a[4] + 7*a[1] + a[0] + 7*a[2] + 8*a[3] + 6*a[9] == 5004)
s.add(2*a[8] + 5*a[6] + 5*a[5] + 5*a[4] + 9*a[3] + 5*a[0] + 9*a[1] + a[2] + 5*a[7] + a[9] == 4490)
s.add(6*a[8] + 7*a[7] + 5*a[6] + 6*a[3] + 4*a[1] + 6*a[0] + 8*a[2] + 6*a[4] + 8*a[5] + 7*a[9] == 5936)
if s.check() == sat:
    ans = s.model()
    for i in range(0,10):
        print(chr(ans[a[i]].as_long()), end="")
else:
    print("no")

运行出来其中一块,根据题目条件的意思,那就是缺少的就是NSSCTF{}包起来就好了

NSSCTF2025入门题目-Debug

ida打开

追到process_blocks函数中

根据传参,追到encrypt中

就是一个skip32的加密过程

在这里打下断点,因为v4此时是经过加密的结果,因此只要找到此时寄存器的值即可

追到var_30找到flag

NSSCTF2025入门题目-Vm~

就是按照opcode_1里的数组进行一些的操作后,与_data_start_进行比较,根据这个顺序进行复原即可

targets = [0x67,0x29,0x29,0x2A,0x6D,0x46,0x01,0x03,0x17,0x8E,0x78,0x5A,0x15,0x53,0x0C,0x66,0x7D,0x46,0x0C,0xDA,0x3A,0x07]
opcodes = [1,3,3,2,1,5,3,3,2,1,1,2,3,2,3,4,1,2,3,4,1,3]
flag = []
for target, opcode in zip(targets, opcodes):
    if opcode == 1:
        original = target - 25
    elif opcode == 2:
        original = target + 25
    elif opcode == 3:
        original = target ^ 0x7A
    elif opcode == 4:
        original = target // 2
    elif opcode == 5:
        original = target
    else:
        original = 0
    flag.append(chr(original))
print(''.join(flag))

NSSCTF2025入门题目-Tea

就是一个tea加密,找到key,enc,delta即可

直接写个tea的解密脚本即可

import struct
def tea_decrypt(cipher: int, key: list) -> int:
    delta = 4277588  
    v0 = cipher & 0xFFFFFFFF 
    v1 = (cipher >> 32) & 0xFFFFFFFF
    sum_val = delta * 32 
    k0, k1, k2, k3 = key
    for _ in range(32):
        temp = ( (v0 + sum_val) ^ ((v0 << 4) + k2) ^ ((v0 >> 5) + k3) ) & 0xFFFFFFFF
        v1 = (v1 - temp) & 0xFFFFFFFF
        temp = ( (v1 + sum_val) ^ ((v1 << 4) + k0) ^ ((v1 >> 5) + k1) ) & 0xFFFFFFFF
        v0 = (v0 - temp) & 0xFFFFFFFF
        sum_val = (sum_val - delta) & 0xFFFFFFFF
    return (v1 << 32) | v0
def decrypt_flag(key: list, enc: list) -> str:
    ciphers = []
    for i in range(0, len(enc), 2):
        low = enc[i]      
        high = enc[i + 1] 
        ciphers.append( (high << 32) | low )  
    plain_bytes = b""
    for cipher in ciphers:
        plain = tea_decrypt(cipher, key)
        plain_bytes += struct.pack("<Q", plain) 
    plain_bytes = plain_bytes.rstrip(b"\x00")
    return plain_bytes.decode("ascii", errors="replace")  
key_1 = [
    0xDEADBEEF,  
    0xBAADF00D,    
    0xDEADC0DE,   
    0xDEAD10CC     
]
enc_0 = [
    0xF0006EE4, 0xBE9A7391,
    0x602AF1CA, 0x83748F0E,
    0x346C8EE0, 0x36DE99D7,
    0x90C4868B, 0x59C40BC2
]
flag = decrypt_flag(key_1, enc_0)
print(f"flag: {flag}")

NSSCTF2025入门题目-pyc

die看一眼

先去用Pyinstaller解包

3.12版本的,把魔法头补一下

用pycdc直接复原

找到加密的函数在extra.cul中,在库中找到补全魔法头,用pycdc进行还原

写个脚本进行复原

enc = [
    52, 41, 41, 57, 46, 60, 1, 10, 3, 25,
    37, 19, 9, 37, 10, 3, 14, 18, 21, 20,
    37, 24, 3, 14, 31, 25, 21, 30, 31, 7
]
flag = ''.join([chr(num ^ 122) for num in enc])
print( flag)

NSSCTF2025入门题目-Maze

就是一个迷宫图,找到迷宫和起点终点即可

追到move_player的check_move中,找到迷宫

在player和taget中找到起点终点

写个脚本计算路程

import hashlib
from collections import deque
def solve_binary_maze():
    binary_str = "0000000000011011101001001010100111101110000100001001110111100100010000011111111000000000100000000000"
    def parse_binary_maze(binary_str):
        if len(binary_str) < 100:
            binary_str += "0" * (100 - len(binary_str))
        maze = []
        for i in range(10):
            start = i * 10
            end = start + 10
            row = [int(c) for c in binary_str[start:end]]
            maze.append(row)
        return maze
    maze = parse_binary_maze(binary_str)
    print("解析后的10x10迷宫:")
    for i, row in enumerate(maze):
        print(f"行{i}: {row}")
    print("\n可视化迷宫:")
    print("(■=障碍, □=可通行)")
    for row in maze:
        print("".join(["■" if c == 0 else "□" for c in row]))
    start = None
    for y in range(10):
        for x in range(10):
            if maze[y][x] == 1:
                start = (y, x)
                break
        if start:
            break
    end = None
    for y in range(9, -1, -1):
        for x in range(9, -1, -1):
            if maze[y][x] == 1:
                end = (y, x)
                break
        if end:
            break
    print(f"\n自动识别的起点: (y={start[0]}, x={start[1]})")
    print(f"自动识别的终点: (y={end[0]}, x={end[1]})")
    directions = [
        ('d', (0, 1)),   
        ('s', (1, 0)),   
        ('a', (0, -1)),  
        ('w', (-1, 0))   
    ]
    queue = deque()
    visited = set([start])
    queue.append((start[0], start[1], "", visited.copy()))
    def is_valid(y, x):
        return 0 <= x < 10 and 0 <= y < 10 and maze[y][x] == 1
    while queue:
        y, x, path, visited = queue.popleft()
        if (y, x) == end:
            return {
                'path': path,
                'length': len(path),
                'flag': f"NSSCTF{{{hashlib.md5(path.encode()).hexdigest()}}}"
            }
        for move, (dy, dx) in directions:
            ny, nx = y + dy, x + dx
            next_pos = (ny, nx)
            if is_valid(ny, nx) and next_pos not in visited:
                new_visited = visited.copy()
                new_visited.add(next_pos)
                queue.append((ny, nx, path + move, new_visited)) 
    return None
if __name__ == "__main__":
    result = solve_binary_maze()
    if result:
        print("\n迷宫求解结果:")
        print(f"最短路径: {result['path']}")
        print(f"路径长度: {result['length']} 步")
        print(f"Flag: {result['flag']}")

NSSCTF2025入门题目-JS太鼓达人

打开html是个游戏

找到程序的源代码在taiko.js中

发现采用了混淆

经过观察,在gameEnd中找到一个scoreNumber的判定,猜测是达成分数,直接修改大于0

随便点一下,然后听歌就可以了

NSSCTF2025入门题目-XTea

追到check_flag中,找到一个xtea的加密,找到对应的ciphertext,key,delta即可

直接写个脚本进行解密

def xtea_decrypt(v, key):
    v0, v1 = v
    k0, k1, k2, k3 = key
    delta = 0x9E3779B9
    sum_val = delta * 32
    for _ in range(32):
        v1 -= (v0 + ((v0 >> 5) ^ (16 * v0))) ^ (key[(sum_val >> 11) & 3] + sum_val)
        v1 &= 0xFFFFFFFF
        sum_val -= delta
        v0 -= (v1 + ((v1 >> 5) ^ (16 * v1))) ^ (key[sum_val & 3] + sum_val)
        v0 &= 0xFFFFFFFF
    return [v0, v1]
def xtea_encrypt_verify(v, key):
    v0, v1 = v
    k0, k1, k2, k3 = key
    delta = 0x9E3779B9
    sum_val = 0
    for _ in range(32):
        v0 += (v1 + ((v1 >> 5) ^ (16 * v1))) ^ (key[sum_val & 3] + sum_val)
        v0 &= 0xFFFFFFFF
        sum_val += delta
        v1 += (v0 + ((v0 >> 5) ^ (16 * v0))) ^ (key[(sum_val >> 11) & 3] + sum_val)
        v1 &= 0xFFFFFFFF
    return [v0, v1]
key_hex = "0D 00 00 00 00 00 00 00 07 00 00 00 21 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"
key_bytes = bytes.fromhex(key_hex)
if len(key_bytes) != 32:
    print(f"密钥长度错误: 预期32字节,实际{len(key_bytes)}字节")
else:
    key = [
        int.from_bytes(key_bytes[0:4], byteorder='little'),   
        int.from_bytes(key_bytes[4:8], byteorder='little'),  
        int.from_bytes(key_bytes[8:12], byteorder='little'),  
        int.from_bytes(key_bytes[12:16], byteorder='little')  
    ]    
    print("修正后解析的密钥(十六进制):")
    print([hex(k) for k in key])
    ciphertext = [
        0x590D36D1, 0x6FA9B5E2, 
        0xDA7190AD, 0xC54B0AA0, 
        0xADA5ED54, 0x4AD07F84, 
        0x8A4CF3C0, 0x7FEFB22F
    ]
    plaintext_blocks = []
    for i in range(0, 8, 2):
        block = [ciphertext[i], ciphertext[i+1]]
        decrypted = xtea_decrypt(block, key)
        plaintext_blocks.extend(decrypted)
    valid = True
    for i in range(0, 8, 2):
        original_block = [ciphertext[i], ciphertext[i+1]]
        encrypted_block = xtea_encrypt_verify([plaintext_blocks[i], plaintext_blocks[i+1]], key)
        if encrypted_block != original_block:
            valid = False
            print(f"块{i//2}验证失败: 预期{original_block},实际{encrypted_block}")
    if not valid:
        print("解密验证失败,无法生成正确的flag")
    else:
        flag_bytes = b""
        for block in plaintext_blocks:
            flag_bytes += block.to_bytes(4, byteorder='little', signed=False)
        printable_flag = []
        for b in flag_bytes:
            if 32 <= b <= 126: 
                printable_flag.append(chr(b))
            else:
                printable_flag.append(f"\\x{b:02x}") 
        print(''.join(printable_flag))

NSSCTF2025入门题目-Unity

一个用Unity做的游戏

玩一下发现根本过不了

发现是mono框架的,那就直接找源代码进行修改

直接找到程序,用dnSpy打开

找到GameManager,编辑加分的方法,变成一次100

修改之后编译保存

但是不知道为什么就是显示不完全,找了半天找不到,没办法直接用取证的工具爆搜了

也算是补全了

NSSCTF2025入门题目-AES

直接查看伪代码,标准的aes,找到密文v6和密匙,注意这里的密文是小端序,需要调整顺序

NSSCTF2025入门题目-DES

也是直接查看伪代码

这里分析代码逻辑,标准的des,就是将明文拆成两部分去进行对比,进行分开解密,v10为密文,v8为密匙

NSSCTF2025入门题目-花指令

打开程序发现多处需要修改的地方

第一处花指令,直接将跳转nop

第二处花指令

将跳转擦除

第三处花指令,jz和jnz的永真跳转

直接nop掉

找到key

写一个脚本进行解密

def decrypt(ciphertext, key):
    key_len = len(key)
    plaintext = []
    for i, c in enumerate(ciphertext):
        key_char = ord(key[i % key_len])
        plain_char = c ^ key_char
        plaintext.append(chr(plain_char) if 32 <= plain_char <= 126 else f"\\x{plain_char:02x}")
    return ''.join(plaintext)
key = "Ciallo"
print(f"使用密钥: {key}")
print("=" * 50)
answer1_part1 = [
    0, 0,  # 索引0和1缺失
    50, 47, 56, 41, 56, 93, 86, 88, 94, 9, 33, 13
]
valid_answer1_part1 = [v for v in answer1_part1 if v is not None]
result1 = decrypt(valid_answer1_part1, key)
print(f"第一个answer1解密结果: {result1}")
print(f"对应密文值: {valid_answer1_part1}")
answer2 = [
    ord('&'), ord('D'), 0x0a, ord('^'), ord('\\'), ord('_'), ord('n'), ord(']'),
    2,
    ord(']'), ord('U'), ord('B'), ord('"'), ord('P')
]
result2 = decrypt(answer2, key)
print(f"flower_2解密结果: {result2}")
print(f"对应密文值: {answer2}")
print("-" * 50)
answer3 = [
    0,  # 索引0缺失
    92, 76, 84, 8, 86, 114, 95, 80, 95, 92, 11, 118, 8, 83, 17
]
valid_answer3 = [v for v in answer3 if v is not None]
result3 = decrypt(valid_answer3, key)
print(f"flower_3解密结果: {result3}")
print(f"对应密文值: {valid_answer3}")

第一部分少了两个,最后一部分的验证少了第一个字节,动调一个个试一下就好

NSSCTF2025入门题目-SMC

看到smc的特征函数,可以直接进行解密,或者使用动调调试,这题有反调试,所以写脚本

import idautils
import idc
import idaapi
def decrypt_and_patch_flag(start_addr, size=395, key=0x99):
    decrypted = []
    for i in range(size):
        addr = start_addr + i
        byte = idc.get_wide_byte(addr)
        decrypted_byte = byte ^ key
        decrypted.append( (addr, decrypted_byte) )
    for addr, b in decrypted:
        if 0x20 <= b <= 0x7E:
            print(chr(b), end="")
        else:
            print(f"[{b:02X}]", end="")
    print("\n")
    modified = 0
    for addr, b in decrypted:
        idc.patch_byte(addr, b)
        modified += 1
flag_start = 0x00007FF7FB9914A1
decrypt_and_patch_flag(flag_start)
    

还原之后看见数据,为汇编中有异或

将之前的数据进行异或处理

毕竟是新生赛,确实不难,但是就是有点做着呛

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值