vsCTF2023

# PREFACE: 快结束了才知道,反正么挺快做了三个题,虽然讲实话很多东西真没看懂,但是逆向么出了就行…
# 后面的三个题解好少… 先看别的地方的题去了…
# ps. 这题怎么越做越多…

# x0rr3al

# 早知道 c 语言有一个 main 调用 main 的操作,似乎是为数不多 c++ 不支持的 c 操作?但是这里好像第一次见了?

存在反调,可以下掉反调看 check,或者直接看逻辑

sub_5560774764F7 : 一个简单异或 0x12

sub_55607747650A : 递归异或一个初始化好的表

单字节加密 flag,全是异或,这里不需要提取,直接爆破即可:

a = '=>8566#>8=).(;9?6.(;9?'
# for i in a:
#     print(chr(ord(i) ^ 0x5A),end='')
# print()
b = f"af&`f2`!d!`a#|u2fz#'2qz&~#2j\"``!s~333"
# for i in b:
#     print(chr(ord(i) ^ 0x12),end='')
dest = 's3cR3ts3vsctfvsctiamfrnow0kkeyw0wkeyw'
lld = [ 0x7E, 0x7B, 0x6B, 0x7C, 0x6E, 0x73, 0x7F, 0x3B, 0x3C, 0x63,
  0x57, 0x3C, 0x66, 0x7C, 0x39, 0x57, 0x6C, 0x3B, 0x6A, 0x7D,
  0x6F, 0x6F, 0x3B, 0x7A, 0x7B, 0x57,  0x3C, 0x7A, 0x3B, 0x57, 0x66, 0x38, 0x57, 0x65, 0x3C, 0x7C,
  0x6B, 0x60, 0x57, 0x6E, 0x38, 0x7A, 0x57, 0x7C, 0x60, 0x3B,
  0x57, 0x3B, 0x39, 0x3B, 0x3B, 0x3F, 0x75]
print(len(lld))
# for i in range(len(lld)):
#     print(chr(lld[i] ^ 0x12 ^ ord(dest[11]) ^ ord(dest[0]) ^ ord(dest[22]) ^ ord(dest[33]) ^ ord(dest[44])),end='')
for i in range(0xff + 1):
    for j in lld:
        print(chr(i ^ j),end='')
    print()
# vsctf{w34k_4nt1_d3bugg3rs_4r3_n0_m4tch_f0r_th3_31337}

#

# challange

用比较复杂的 stl(主要是 vectorstring )进行数据操作,做了个类似 RSA 的 乘方+取模 然后加点异或生成了一个 vector 用于加密,但是加密逻辑只有异或,flag 是 50 位的

image-20230925110429523

这里不需要硬逆逻辑,下掉 ptrace 反调(这里原本有 exit (0); 已经 nop 掉了)

image-20230925110532965

在 check 的地方把检查逻辑改掉(改成如果不相等则退出)

image-20230925110635140

提取异或的 key 数据

n
print(hex(get_reg_value("ebx")) , end = ', ')

直接梭就行(这里输入的是全 1 的 flag,flag 也刚好没有 1,可以多用几个试几次):

enc = [149, 148, 5, 88, 128, 22, 47, 70, 184, 117, 311, 57, 145, 224, 32, 112, 77, 185, 25, 59, 79, 4, 31, 184, 156, 79, 241, 179, 162, 68, 119, 244, 92, 109, 29, 47, 123, 154, 33, 224, 223, 125, 159, 194, 116, 63, 4, 246, 199, 250, 0]
# for i in range(len(enc)):
#     print(chr(enc[i] ^ i),end='')
a = '11111111111111111111111111111111111111111111111111'
b = [0xd2, 0xd6, 0x57, 0x1d, 0xd7, 0x5c, 0x78, 0x22, 0xe7, 0x7, 0x131, 0x39, 0x90, 0x9f, 0x25, 0xd, 0x23, 0xb8, 0x58, 0x55, 0x9, 0x6a, 0x6d, 0xe6, 0xc0, 0xe, 0xa5, 0xf6, 0xfa, 0x1, 0x2f, 0xb3, 0x8, 0x3, 0x7c, 0x6c, 0x25, 0xcc, 0x4f, 0x85, 0xab, 0x1, 0xfe, 0xbf, 0x4, 0x5a, 0x70, 0x94, 0xc9, 0xb6]
# print(0xd2 ^ ord('1'))
# print(227 ^ 149)
# print(chr(227 ^ 149))
for i in range(len(b)):
    print(chr(enc[i] ^ b[i] ^ ord('1')),end='')
# vsctf{fUnC710N4L_0p_w_Competitive_Prog_TEMPLATES?}

# teenage-wasm

# 说实话第一次做 wasm…

插件: Release Version 2.1.0 · nneonneo/ghidra-wasm-plugin (github.com)

选择的是 Ghidra + wasm 插件的反编译方案,还是比较清晰的

image-20230925111041089

可以拿到一个 js 代码,和一个 wasm 代码,这里找不到 button 的处理 handle,纠结了很久,然后友 web 手说可能是 wasm 里面注册了监听,orz 真该学学 web 了…

js 代码中大概是 wasm-bindgen 编译的与 wasm 交互的产物,只负责中间件,将字符串共享给 wasm,并接收共享字符串

可以直接来看 wasm,代码很多,rust 编译的也相对抽象,经过前面说的可能是监听的 button 可以翻翻代码,然后发现了这个

image-20230925111803725

flush_messages

image-20230925111851725

加密逻辑也很显眼…

虽然其实还并不是狠看懂这个怎么传回去的,但是提取数据异或一下真的就是 flag 了…(他真的很喜欢异或)

a_list = ["7a",
"5158577471345867",
"4a77746f79675a70",
"6a4d5a776d716272",
"46625f373333316d",
"73617765766f6c69",
]
b_list = ["07",
"1f16203f4345352d",
"123a201a2e170515",
"072229441a103d06",
"760c00445a6c5c1e",
"47160c03020c1f1f",
]
flag = ''
for i in range(6):
    a = [int(a_list[i][j: j + 2], 16) for j in range(0, len(a_list[i]), 2)]
    b = [int(b_list[i][j: j + 2], 16) for j in range(0, len(b_list[i]), 2)]
    for j in range(len(a)):
        flag += chr(a[j] ^ b[j])
print(flag[::-1])
# vsctf{w4sm_is_n0t_aw3some_pWuTMXJmq2KwNN}
# 9-26: 感觉本来 wasm 就见得不多,会做的更是少,还是不要草草结束了这个题,把他给逆完整一点

直觉上 flesh_message 既然找不到 x-ref ,应该还是有更多处理逻辑的,首先是这里的比对

image-20230926204837431

local_18 拿到了 param2(即用户的一个输入),与 admin 字符串进行了比对,如果不是 admin 会返回 Login fail 的提示

image-20230926205045674

image-20230926205146253

# (可以右键更换数据类型)

这个地方感觉有机会,看看下面,找到了类似的结构:

image-20230926205948905

但是这里没那么明显,先试试我怎么出的:

这里除去 admin 已经没有明显的全局变量了,能包含有字符信息的内容不多,然后突然意识到这里全都是可见字符:image-20230926210857339

那其实很蹊跷了,打印一下看看

image-20230926210952849

感觉就很明显了,有明显的英文语法痕迹(?)

逆转过来:

image-20230926211040498

这个就是密码…

image-20230926211059432

回来看看逻辑,到底放在哪里

前面没注意,但是这里有个很明显的把参数提取成 utf-8 的操作:

image-20230926211238954

然后存储 local_18 -> local_68 在下面进行比较

还是对这些符号不够敏感…