[DSACTF2022七月]ezgetshell【上】

[DSACTF2022七月]ezgetshell【上】

目录

0x01题目简单介绍:

打开题目:

有一个图面上传图面查看的功能

  1. 很容易想到可能是考察文件上传绕过的能力,但是我们通过上传文件发现,人家并不会提供上传后文件的位置,也就是说即便是我们上传上去了木马,也被执行,但是我们找不到木马的位置,到此处就说明第一条思路断了。

  2. 既然上传不能走得通,那就看一下能不能从查看图片中发现什么信息。首先通过F12发现,人家是通过调用upload.php来实现上传,通过file.php来实现查看图片的。

  3. 具体过程是一段js代码来发起请求的,我们着重看一下file.php的调用

    $('.search').click(function(){
           $('.result').children().remove();
           $('.result').text('');
           var content = $('.box').val();
           console.log(content);
           $.ajax({
             type: "GET",
             // dataType: "text",
             contentType: "application/x-www-form-urlencoded",
             url: "./file.php",
             cache: false,
             data: "f="+content,
             success: function(result) {
               $('.result').append(result);
             },
             error: function() {
               $('.result').text('error!!');
             }
           });
         })
    

    可以看出参数是f=参数请求方法是get,当然通过抓包也可以看到请求的

    抓包可以看出来人家是有一个另外的参数的,这个影响不大的。

  4. 了解了人家的get图片的方法后,我们试一下能不能用这个file.php读取到其他文件(这个web就两个功能,上传→ 上传木马,查看/读取→ 读取源码或者敏感信息,再没有其他功能可供利用了。)

  5. 读取payload

    file.php?f=index.php

    得到图片的base64,解码后得到index.php的源码:

    用同样的方法得到另外的两个文件的源码

    /file.php?f=file.php
    /file.php?f=upload.php

    得到源码:file.php

    upload.php:

    ps : 网页的base64编码不需要自己去单独解码,直接从前端源码中双击就能看到转义后的结果

    可以看出这两个文件都调用了一个class.php的文件,这里猜测大概率是和反序列pop链有关的。

    重复上面的方式得到这个class.php的文件的源码:

    /file.php?f=class.php
    

    得到源码:

0x02审计class.php文件

这个class.php文件有三个类

Upload类

class Upload {
        public $f;
        public $fname;
        public $fsize;
        function __construct(){
            $this->f = $_FILES; # 当new一个新对象的时候就把保存的文件复制给$f
        }
        function savefile() {  
            $fname = md5($this->f["file"]["name"]).".png";  # 将文件的名字md5之后然后在加上.png。 这里可以触发__toString()方法,咱不知道有无用处
            if(file_exists('./upload/'.$fname)) {  # 如果文件存在,就删除文件
                @unlink('./upload/'.$fname);
            }
            move_uploaded_file($this->f["file"]["tmp_name"],"upload/" . $fname); # 将新文件移动到新的位置 ”upload/“
            echo "upload success! :D";  # 打印成功
        } 
        function __toString(){  //这个类在程序中没有被用上,属于是专门给我们准备的
            $cont = $this->fname;
            $size = $this->fsize;
            echo $cont->$size;
            return 'this_is_upload';
        }
        function uploadfile() {  # 这个是被调用的函数,也是第一个执行的方法
            if($this->file_check()) { 
                $this->savefile(); # 如果文件检测成功了,就调用文件保存方法
            } 
        }
        function file_check() { 
            $allowed_types = array("png");  #规定的允许类型是png
            $temp = explode(".",$this->f["file"]["name"]); # 将字符串以"."为标志打散为数组,分别存储到file和name中
            $extension = end($temp); 
            if(empty($extension)) {  # 如果没有后缀,就执行下面的第一条
                echo "what are you uploaded? :0";
                return false;
            }
            else{ 
                if(in_array($extension,$allowed_types)) { # 如果后缀符合,就执行下面的语句
                    $filter = '/<\?php|php|exec|passthru|popen|proc_open|shell_exec|system|phpinfo|assert|chroot|getcwd|scandir|delete|rmdir|rename|chgrp|chmod|chown|copy|mkdir|file|file_get_contents|fputs|fwrite|dir/i';
                    $f = file_get_contents($this->f["file"]["tmp_name"]); # 取出文件内容到f中
                    if(preg_match_all($filter,$f)){ # 如果文件匹配成功,就报错并退出,全局匹配
                        echo 'what are you doing!! :C';
                        return false;
                    }
                    return true; 
                } 
                else { # 如果后缀不符合就退出
                    echo 'png onlyyy! XP'; 
                    return false; 
                } 
            }
        }
    }

\$_FILES["file"]["tmp_name"] 表示上传的文件,其中tmp_name是上传后临时保存的变量。

该类被创建的时候就会读取当前的文件,并保存到变量 \$f中,类的入口是uploadfile()此方法会调用file_check()方法,通过检测文件的后缀和文件内容是否合格,然后调用savefile()方法给文件名字,并保存它。

Show类

class Show{
        public $source;
        public function __construct($fname)
        {
            $this->source = $fname; #  文件名字传入source变量中
        }
        public function show() # 类的入口
        {
            if(preg_match('/http|https|file:|php:|gopher|dict|\.\./i',$this->source)) {
                die('illegal fname :P');
            } else {
                echo file_get_contents($this->source);
                $src = "data:jpg;base64,".base64_encode(file_get_contents($this->source));
                echo "<img src={$src} />";
            }

        }
        function __get($name) # 获取不存在变量或者私有变量就触发该魔术方法,name为这个变量的名字
        {
            $this->ok($name);
        }
        public function __call($name, $arguments) # 当调用不存在的方式时就调用该魔术方法,比如上面的ok函数,其中argument变量中存在这不可访问的name方法的参数
        {
            if(end($arguments)=='phpinfo'){ //提供更多的数据
                phpinfo();
            }else{
                $this->backdoor(end($arguments)); //后门函数
            }
            return $name;
        }
        public function backdoor($door){
            include($door);
            echo "hacked!!";
        }
        public function __wakeup() //执行反序列化时候就执行这个方法
        {
            if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
                die("illegal fname XD");
            }
        }
    }

调用ok函数的时候触发__call()函数其中$name形参就是ok$arrgument就是传入给okname变量

Test类:

class Test{
        public $str;
        public function __construct(){ //类被创建的时候赋值
            $this->str="It's works";
        }
        public function __destruct()
        {
            echo $this->str; //被销毁时echo $str
        }
    }

0x03phar反序列化准备工作:

phar反序列化:

phar反序列化即在文件系统函数file_exists()is_dir()等)参数可控的情况下,配合phar://伪协议,可以不依赖unserialize()直接进行反序列化操作。

phar反序列化优点:

可以不管文件的后缀,只要调用过文件系统函数就可以,适合这种后缀不可控的情况下

phar反序列化可以加密,从而绕过过滤

所受影响的函数:

file_get_contents() 本题所用到的函数,作用是将文件读入一个字符串中。

fileatime,filecttime,file_exists,file_putcontents,file,fopen,is_dir等等

以及对于调用了php_stream_open_wrapper的函数,都存在这样的问题。

利用条件:

  1. 反序列化的phar文件要能上传到服务端

  2. 要有可用的魔术方法作为“跳板”

  3. 文件操作函数可控,且:,/,phar等字符可用

利用原理:

phar序列化文件简单来说就是一个文件头和一个反序列化文件

通过phar://反序列化这个文件的时候就有可能调用魔术方法比如:__wakeup然后就是代码执行。

最终影响就是任意代码执行

phar文件制作:

制作phar文件我们使用的是phar类

<?php
@unlink("shell.phar"); //删除已经存在的shell,为了反复使用,@是用来关闭提示的
$phar = new Phar("shell.phar"); //注明自己要生成的phar文件的地址和文件名
$phar->startBuffering(); //开始缓冲的phar文件写入
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub头,是phar文件的标识符,有时候为了过墙,可以添加GIF89a之类的头
$phar->setMetadata($test); //这个$test就是自己需要反序列化的函数
$phar->addFromString("test.txt", "test"); //写入压缩内容,不然无法生成文件
$phar->stopBuffering(); // 将缓冲中的内容写入到文件中
?>

0x04 php session上传准备

创建session文件

在php服务端开启session之后,每次会话服务端都会保存一个会话,这个会话信息保存在ini文件中的session.save_path选项下的,默认为/tem或者/var/lib/php/session中

保存的名字为sess_PHPSESSIONID 其中PHPSESSIONID是会话的cookie上传的。

这个sessionid当在ini文件中session.use_strict_mode为off的时候是可以伪造的,这个值默认是off,可以使用任意sessionid来创建一个session文件

写入session文件

当我们在上传文件的时候,有如下四个ini配置文件值得注意

1. session.upload_progress.enabled = on
2. session.upload_progress.cleanup = on
3. session.upload_progress.prefix = "upload_progress_"
4. session.upload_progress.name = "PHP_SESSION_UPLOAD_PROGRESS"

这个配置官方的解释是 实时监测上传进度

0x05 python脚本编写

会话维持

由于涉及到session的存储,所以我们需要创建一个session会话来保存数据

s=requests.Session()
# 之后发送信息就可以使用s.post() 或者s.get()
# 本例中没看出来有什么用,但是确实学到了

文件发送

当我们需要发送一个没有什么用的文件,但是又需要这个发送文件的操作的时候,可以这样写:

file={"file1":("file.png",b'a'*50*1024)}
s.post(url=url,files=file)

本例中,在文件结构体file中,file1对应的是上传文件表单的name属性,需要和后端对应起来才可以接收到这个表单

后面的元组表示文件部分:file.png是所上传文件的名称,服务端会自动读取,紧接着的就是文件内容。

当然也可以使用io操作来生成一段字符:

import io
filebytes = io.BytesIO(b'a' * 1024 * 50)
files={
                 'file': ('Lxxx.jpg', filebytes)
          }

多线程

由于只是简单的条件竞争,所以这里只是学习一下如何开多个线程就可以了

# 首先引入多线程库
import threading 
# 创建一个要多线程的函数
def fun1(a):
    print(a)

# 创建一个线程并且启动它,其中target是目标函数,args是参数,用元组传入即可
threading.Thread(target=fun1,args=(1)).start()

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本站及文章作者不为此承担任何责任。

本站拥有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经本站允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇