「安恒杯」第二届 NEX 网络安全理论赛 WP


共解出 8 题

COMMON

【简单】签到喵

确实简单,海报下方…. …– .—- .. — ..–.- .– — .-. .—- -..摩斯电码,解码后为 H31IO_WOR1D,提交即可。(说实话第一次知道下划线怎么打)



然后,就没有 common 了。。QAQ


MATH

【简单】凯撒超进化

Vigenère cipher,这次 geekgame 也有,两种方法,一是查表,但说实话不如利用其特性可以根据 nex 这个前缀手动试出来 key 为 ozu。

【中等】2024 爱护你的蟒蛇

打开 round1.py,发现储存 flag 的部分:

1
2
3
4
5
6
7
enc = [……]

def check_flag(text):
text = list(text)
for i in range(len(text)):
text[i] = (ord(text[i]) ^ 0xCC) - 3
return text == enc

写出其的逆过程:

1
2
3
4
5
def de_flag(enc):
text = ""
for i in range(len(enc)):
text += chr((enc[i] + 3) ^ 0xCC)
return text

运行得 flag。



也没了!菜死了我。


PWN

【简单】浮屠塔的出口

nc 连上之后走个迷宫就没了。



PWN 就这一题,其他的题本地打通了,然后忘了 :P


BINARY

【简单】从零开始的 CPP 生活

我不好说,但是。。。我之前为了正好装过 vs,直接打开,vs 帮我做完了。
打开 flag.cpp 后:

1
2
3
4
5
6
7
8
9
#include "flag.hpp"
Flag::Flag() {
flag = "flag{b9bcd94c-2ee1-4e74-b8e2-372a10869adc}";
}

std::string Flag::GetFlag()
{
return this->flag;
}

【中等】开源逆向题喵

打开程序,发现被挡住了,但是背景是像素字!
然后看文件,一个醒目的 flag.h,一打开,发现

1
int flag_pixels[360][480] = {……}

欸,合理怀疑就是背景 flag 图片,写转为 png 脚本:

1
2
3
4
5
6
7
8
from PIL import Image
import numpy as np

flag_pixels = [……]

array = np.array(flag_pixels, dtype=np.uint8)
img = Image.fromarray(array * 255, mode='L')
img.show()

完事,感觉不像预期解,但是有没防,怪。

【简单】假面之下的 Flag

呃呃,拖进 ida -> shift+F12 查看字串 -> 甚至第一个就是。

【困难】愤怒喵 NaN~

我测,我一拖进 ida,main 函数那图一出来,我去,吓人。
还是 shift+F12 查看字串起手,发现两终点:

1
2
.rodata:000000000000B016	00000007	C	N0N0N0
.rodata:000000000000B010 00000006 C G00D!

可以写出判断终点函数:

1
2
3
4
5
def is_success(state):
return b'G00D!' in state.posix.dumps(sys.stdout.fileno())

def is_fail(state):
return b'N0N0N0' in state.posix.dumps(sys.stdout.fileno())

这样不用记地址。
按 f5 反编分析 main 函数,发现以下语句:

1
2
stream = fopen("flag.png", "rb");
fread(&ptr, 1uLL, 0x142uLL, stream);

说明读入了一个大小为 0x142 的 flag.png,可以在 angr 中模拟文件系统,创建一个 flag.png 的符号执行对象:

1
2
3
file_size = 0x142
symbolic_file = angr.storage.SimFile("flag.png", size=file_size)
initial_state.fs.insert("flag.png", symbolic_file)

然后,跑就完事了!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import angr
import sys
from PIL import Image
import io

def Go():
path_to_binary = "./mustangr/problem"
project = angr.Project(path_to_binary)

initial_state = project.factory.entry_state()

file_size = 0x142
symbolic_file = angr.storage.SimFile("flag.png", size=file_size)

initial_state.fs.insert("flag.png", symbolic_file)

simulation = project.factory.simgr(initial_state)

def is_success(state):
return b'G00D!' in state.posix.dumps(sys.stdout.fileno())

def is_fail(state):
return b'N0N0N0' in state.posix.dumps(sys.stdout.fileno())

simulation.explore(find=is_success, avoid=is_fail)

if simulation.found:
solution_state = simulation.found[0]
flag_content = solution_state.fs.get("flag.png").concretize()
print("[+] Success! The flag content is: {}".format(flag_content))
image = Image.open(io.BytesIO(flag_content))
image.save("output.png")
else:
print("[-] Could not find the solution")

if __name__ == "__main__":
Go()


其实 vmp 那题我也在尝试,已经打了很多函数了,但确实时间不够,没把逻辑看完 QAQ。


小结

感谢 NEX 奇妙の小题。