RCTF 2024
本文最后更新于13 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

1.2048

代码审计,每轮会将获得分数为输入的sorce,上限为当前得分,初次上限为1w,那么每次成功分数会翻倍,玩个几次即可到达100w分

RCTF{you_are_2048_master}

2.bloker_vm

一开始我看到爆红以为有花,后面up以后找到了sub_411A10

3个case:rc4,xor,移位

因为反调试所以就懒得去找顺序,3个case不算多直接测就行

最后顺序是rc4移位xor

注意rc4的密钥长度是18,但是给的密钥是19位

def KSA(key):
    S = list(range(256))
    j = 0
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i], S[j] = S[j], S[i]
    return S


def PRGA(S):
    i, j = 0, 0
    while True:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        K = S[(S[i] + S[j]) % 256]
        yield K
def RC4Decrypt(key, text):
    S = KSA(key)
    keystream = PRGA(S)
    res = []
    for char in text:
        res.append(char ^ next(keystream))
    return bytes(res)
#示例
key = b'thisisyoursecretke'
plaintext = [0x80,0x5,0xE3,0x2F,0x18,0x2F,0xC5,0x8C,0x25,0x70,0xBC,0x5,0x1C,0x4F,0xF2,0x2,0xE5,0x3E,0x2,0x2F,0xE5,0x11,0xA3,0xC0]
Rc4encrypt = RC4Decrypt(key, plaintext)
# print(Rc4encrypt)
xor_data = bytearray(Rc4encrypt)
for i in range(len(xor_data)):
    xor_data[i] = ((xor_data[i] >> 6) | (xor_data[i] << 2)) & 0xFF
    print(chr(xor_data[i] ^ 0x7D),end='')

RCTF{a_baby_debug_bloker}

3.PPTT

首先观察这两个函数 他们先对我们的输入进行处理 我们通过动调查看返回值

先序遍历: 0137fg8hi49jkalm25bnc6de
中序遍历: f7g3h8i1j9k4lam0nb5c2d6e
后序遍历: fg7hi83jk9lma41nbc5de620

可以看到这里是对输入进行先序和中序遍历

下面这一段是对数组进行交换 这里动调会死 应该是加了反调试 我们使用python模拟一下(这里的v29数组对应的是中序遍历的返回值)

from collections import deque


# 定义二叉树节点
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None


# 层序方式建立二叉树
def build_tree_level_order(data):
    if not data:
        return None
    root = TreeNode(data[0])
    queue = deque([root])
    i = 1
    while queue and i < len(data):
        node = queue.popleft()
        if i < len(data):
            node.left = TreeNode(data[i])
            queue.append(node.left)
            i += 1
        if i < len(data):
            node.right = TreeNode(data[i])
            queue.append(node.right)
            i += 1
    return root


# 先序遍历
def preorder(node, result):
    if node:
        result.append(node.val)
        preorder(node.left, result)
        preorder(node.right, result)


# 中序遍历
def inorder(node, result):
    if node:
        inorder(node.left, result)
        result.append(node.val)
        inorder(node.right, result)


# 后序遍历
def postorder(node, result):
    if node:
        postorder(node.left, result)
        postorder(node.right, result)
        result.append(node.val)


# 主程序
if __name__ == "__main__":
    chars = '0123456789abcdefghijklmn'
    tree = build_tree_level_order(chars)

    pre_result, in_result, post_result = [], [], []
    preorder(tree, pre_result)
    inorder(tree, in_result)
    postorder(tree, post_result)

    print("先序遍历:", ''.join(pre_result))
    print("中序遍历:", ''.join(in_result))
    print("后序遍历:", ''.join(post_result))

def swap_data(data):
    v29 = list(data)
    swaps = [
        (15, 16),
        (7, 17),
        (18, 8),
        (3, 19),
        (20, 9),
        (21, 22),
        (10, 4),
        (1, 23),
        (11, 12),
        (5, 13),
        (14, 6),
        (2, 0),
    ]
    for a, b in swaps:
        v29[a], v29[b] = v29[b], v29[a]
    return ''.join(v29)

data = "f7g3h8i1j9k4lam0nb5c2d6e"
result = swap_data(data)
print("After swap:", result)
# 先序遍历: 0137fg8hi49jkalm25bnc6de
# 中序遍历: f7g3h8i1j9k4lam0nb5c2d6e
# 后序遍历: fg7hi83jk9lma41nbc5de620
# After swap: gefckamb52hl48in01j396d7

根据约束z3求解看看结果,是一个多解题,我的思路是查看返回值缩小答案范围

通过返回值可知v24里面有字符‘T’,‘{’,v25里面有‘C’,‘F’,‘}’这几个flag的标志字符

我们给flag加上束缚再次跑一下

from Crypto.Util.number import *
from z3 import *

v17 = BitVec('v17', 64)
v18 = BitVec('v18', 64)
v19 = BitVec('v19', 64)
v20 = BitVec('v20', 64)
v23 = BitVec('v23', 64)
v24 = BitVec('v24', 64)
v25 = BitVec('v25', 64)

s = Solver()

s.add(v20 == v24 & v23)
s.add(v19 == (v24 & v23 | v25 & v23) + 65670)
s.add(v18 == (v25 & v23 ^ v25 & v24) - 1131796)
s.add(v17 == v24 & v23 ^ v25 & v23)
# s.add((v24 & v23 & (~(v24 | v23) | v25 & v23 | v25 & v24 & ~v18) | v25 & v24 & v18) != 0x67437616)
s.add((v23 ^ (v20 & ~v18 | v20 & ~v19 | v17 & v19 | v25 & v23 & ~v18)) == 0x400010000622000)
s.add((v18 ^ (v19 - v20)) == 0x2100A0203EFBB8B)
s.add((v17 ^ v19 ^ v20) == 0x4083102108E)
s.add((v19 ^ v17) - v18 == 0x1551566F3C6485ED)
s.add((v18 ^ v19 ^ v25 & v24) == 0x40836ECAB9A)
s.add((v17 ^ v20) - v18 == 0x3E51566F3C718563)
s.add(v23 - v24 == 0x1AEFF6FDFC121BF1)
s.add((v25 + v24 + v23) % 10 == 8)

while s.check() == sat:
    model = s.model()
    tmp = long_to_bytes(model[v25].as_long())
    tmp1 = long_to_bytes(model[v24].as_long())
    s.add(v25 != model[v25])
    if tmp.find(b'C') == -1 or tmp.find(b'F') == -1 or tmp.find(b'}') == -1:
         continue
    if tmp1.find(b'T') == -1 or tmp1.find(b'{') == -1 == -1:
        continue

    mid1 = long_to_bytes(model[v23].as_long())
    mid2 = long_to_bytes(model[v24].as_long())
    mid3 = long_to_bytes(model[v25].as_long())
    # print(mid1[::-1])
    # print(mid2[::-1])
    # print(mid3[::-1])

    str1 = '0123456789abcdefghijklmn'
    str2 = 'gefckamb52hl48i0n1j396d7'

    mid = mid1[::-1] + mid2[::-1] + mid3[::-1]
    flag = ''
    for i in range(24):
        flag += chr(mid[str2.find(str1[i])])
    if all(32 <= ord(c) <= 126 for c in flag):
        print(flag)

注意本题还有一个地方卡了我很久,也是后面看了大佬wp才知道原因

看这里的str1,看似可以通过它减小flag的范围,但是得出的结果是错误的,我使用正确的flag模拟str2的生成值以后比较发现这里的值是被修改过的

先序遍历: RCFksdnaq{wtyeuaTsm}qjsp

这里倒数第2位正确的值转换过后应该是‘s’,但是str1里的是‘r’

这个藏起来的全局初始化函数中,会会对第13个执行一个++的操作

导致这里str1的值变了

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇