[CISCN2019 華北賽區 Day1 Web5]CyberPunk

bfengj發表於2020-12-10

知識點

  • 檔案包含
  • 程式碼審計
  • 二次注入,報錯注入

WP

真的很煩,從昨天晚上開始,今天早上想了好幾個小時沒想明白這題怎麼弄flag。實在受不了了看了WP,才發現這flag名字不是/flag而是/flag.txt,草了,又因為這樣的題目白白浪費了幾個小時的時間。

除去flag檔名,這個題目不算難,就是基本的程式碼審計,找二次注入點然後注就完事了。。

首先進入環境,對這個環境的功能稍微瞭解一下,f12看一下原始碼,發現了提示?file?
經過嘗試,發現是檔案包含,利用PHP偽協議讀一下所有的原始碼,還嘗試直接讀/flag檔案,但是發現不行。看了一下index.php的原始碼,發現存在open_basedir的限制。

稍微把那些程式碼都審一下,最終發現了這個change.php:

<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
    $msg = '';
    $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
    $user_name = $_POST["user_name"];
    $address = addslashes($_POST["address"]);
    $phone = $_POST["phone"];
    if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
        $msg = 'no sql inject!';
    }else{
        $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
        $fetch = $db->query($sql);
    }

    if (isset($fetch) && $fetch->num_rows>0){
        $row = $fetch->fetch_assoc();
        $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
        $result = $db->query($sql);
        if(!$result) {
            echo 'error';
            print_r($db->error);
            exit;
        }
        $msg = "訂單修改成功";
    } else {
        $msg = "未找到訂單!";
    }
}else {
    $msg = "資訊不全";
}
?>
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];

可以發現,我們一開始直接下單,傳入的address並沒有進行正則匹配,而是經過一次預編譯就直接送往了資料庫中。而這裡的change.php的這條語句直接把我們傳入的address拿出來拼接到這個update語句中,因此存在二次注入。直接用updatexml的報錯注入來讀/flag.txt就行了。不過因為updatexml的報錯注入存在長度限制,因此還要利用substr的擷取:

' and updatexml(1,concat(1,(select substr(load_file('/flag.txt'),1,32)),1),1)#

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

後記

其實一開始我還以為load_file也受到open_basedir的限制,直接讀/flag沒讀到以為還要繞過open_basedir,想著寫shell但是也沒成功,然後就各種迷。。。這個/flag.txt還是挺坑的。

相關文章