2019 0CTF/TCTF wallbreaker easy 题目理解

前言

等比赛结束之后才敢来看一下题目??。找到了复现环境:
https://github.com/m0xiaoxi/CTF_Web_docker/tree/master/TCTF2019/Wallbreaker_Easy

使用这个环境如果发现就是上传不了文件,查看/var/log/nginx/error.log发现错误提示是权限不够的话,需要在/tmp目录下执行chown www-data .,添加www-data用户…

参考了几篇相关的帖子(就觉得啊…这些大佬怎么什么都能想到…)。

  1. https://www.freebuf.com/articles/web/192052.html
  2. https://xz.aliyun.com/t/4589
  3. https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD

在这之前还看了LD_PRELOAD的相关帖子。这个东西像是已经出来很久了。
看到还有其他的方法来做这个题目。先把通过LD_PRELOAD做的方法记录下来,再接着去看其他方法。

对了…前几天刚看了一个利用imap_open()函数来绕过对disable_function的限制,这个题目恰好也是绕过disable_function的技巧,搞完之后可以整理总结一下其他的绕过技巧还有哪些。((⊙o⊙)我总是在事前想的很好)在禁用的函数里也写了imap_open()。(知识积累是多么重要)

WriteUp

LD_PRELOAD这个环境变量,在php需要起新进程的时候会被查看,然后会根据这个变量的内容,去加载共享对象(.so文件,就类似于windows下的.dll文件)。

上面那个freebuf的帖子里详细描述了这种攻击方式的流程,在这个题目里,只是用了另外一个起新进程的函数,思路是一样的。我在理思路的过程中,简单画了一个流程图。

在这里插入图片描述

总的来说,就是需要控制web起一个新进程,这样LD_PRELOAD环境变量定义的共享对象(攻击者可控)就会被加载,由于共享对象中定义的函数使用__attribute__((constructor))修饰了,所以一旦共享对象被加载,恶意函数就会被执行。从而我们就可以执行任意指令了。
(当然帖子中还写了找到这种方法的整个思路,要怎么去找有没有起新进程,怎么去看执行函数过程中起了几个进程等等)

针对这个题目来说,因为给了我们webshell,我们可以在/tmp/md5($_SERVER['REMOTE_ADDR'])/路径下写文件,但是不能执行系统函数,题目告诉我们要想办法去执行/readflag文件。
做法就是先上传一个.so文件,这个文件就直接是上面的github链接里的文件就可以,通过这个文件中包含的函数来执行任意指令。
然后因为ImageMagick在将bmp编码的图片文件转换为wdp编码的文件的时候,会触发一个新进程,从而就可以执行.so文件中的恶意函数了。

$a=new Imagick();
$a->readImage('123.png');
$a->writeImage('sad.wdp');  //触发新进程

(写的好简单啊??)
在这里插入图片描述

同样的方式再上传一个随便什么的.png图片。

在这里插入图片描述
后台的报错信息如下,但是指令是执行了的。
在这里插入图片描述

最后,再读取目录下的flag.txt文件就可以了。
在这里插入图片描述

方法二

看到的第二种方法没有实际去操作。

这种方式不是去想着绕过disable_functions,而是绕过open_basedir,因为题目限制了只能在open_basedir规定的目录下工作,如果绕过这个限制就可以读取其他目录的文件和文件内容了。

首先利用glob伪协议拿到了一些文件名等信息,然后通过php-fpm在同一个服务器上建立另外一个php进程(不知道这样描述是不是合适的),这个进程是和已经运行的php没关系的,当然也就不会受到open_basedir的限制了。


2019.04.03更新
动手操作了一波,比想象中复杂一点,还是很有收获的。
下面给的第一个参考链接就是描述的这种做法,但是…感觉不是很详细吧。??也可能是我太辣鸡了…

首先上传一个实现了fastcgi类的文件,并在这个文件中添加新建fastcgi的相关代码,并且配置open_basedir=/。这个fastcgi实现的文件github上有很多,我找了参考文献中第二个提到的那个(同时还要上传repo中的另外两个文件CommunicationException.php Response.php,可以看到一些报错和回显信息)。在其中的Client.php文件后面再追加一部分代码:

// 省略Client.php
<?php
   $client = new \EBernhardson\FastCGI\Client('//var/run/php/php7.2-fpm.sock');
   $php_value = "open_basedir=/";
   $cmd = $_POST['cmd'];
   $environment = [
       'REQUEST_METHOD'  => 'POST',
       'SCRIPT_FILENAME' => '/tmp/36b94e1bf70bdfd0a2e47a195261c77e/index.php',
       'PHP_VALUE'       => $php_value,
       'CONTENT_LENGTH'  => strlen($cmd),
       'QUERY_STRING' => http_build_query(['cmd' => $cmd])
   ];
   var_dump($client->request($environment, $cmd));

另外还要再上传一个index.php文件,就是代码中SCRIPT_FILENAME参数对应的那个文件。这个参数应该是给出新建的这个FastcgiClient实例是要向哪个文件去发起请求,这个文件里的内容就是一句话木马。(参考链接的exp部分比我这里提到的多一点,原理是一样的,感觉写太多有点晕??)

在这里插入图片描述

过程就是:
当我们在请求/var/www/html/index.php时,让它包含Client.php,那么Client.php中的代码就会被执行,调用FastCGIClient类,新建一个实例,配置open_basedir=/,去请求/tmp/xxxx/index.php文件,并传递cmd,然后cmd包含的指令就会被执行。
(刚开始不是很理解这个FastCGIClient,现在感觉应该就是有些人实现了这个类,允许开发者可以在原本的php之外再起一个请求,同样是使用php-fpm,但是这个请求有自己的一些配置。就像参考链接3提到的那种需求。这样解释的话,就可以理解为什么这里要使用这个东西来绕过open_basedir,而且还有那么长一个文件。)

希望大家有不理解的,或者我有说错的地方可以留言评论。

贴一下结果图:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

图中的文字标明的一些问题:
这种绕过open_basedir的方法应该算是非预期了…这个方法只有在别人已经做出来的情况下才能用。因为虽然不受目录的限制,但是无法绕过对文件权限的限制。因为原本的/flag文件是只有root用户可读可写的,其他用户没有任何权限,所以即使知道这里有个文件,也不能直接查看到。而当有人用LD_PRELOAD方法做出来之后,他一定会在他的/tmp/xxx目录下复制一个flag的文件,这个文件www-data用户时有权限的,然后就可以用这种方法读到flag值了。


参考

  1. https://balsn.tw/ctf_writeup/20190323-0ctf_tctf2019quals/#wallbreaker-easy
  2. https://github.com/ebernhardson/fastcgi
  3. https://stackoverflow.com/questions/36106419/using-php-fpm-inside-a-php-process

方法三

这种方法是利用了ImageMagickMAGICK_CODER_MODULE_PATH参数特性,这个参数可以定义一个路径,在这个路径下的代码会被用来处理ImageMagick支持的图片类型。
具体那些代码我看不下去了。??

参考

  1. https://github.com/m0xiaoxi/CTF_Web_docker/tree/master/TCTF2019/Wallbreaker_Easy

版权声明:本文为littlelittlebai原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。