PHP网站渗透中的奇技淫巧:检查相等时的漏洞
PHP是现在网站中最为常用的后端语言之一,是一种类型系统 动态、弱类型的面向对象式编程语言。可以嵌入HTML文本中,是目前最流行的web后端语言之一,并且可以和Web Server 如apache和nginx方便的融合。目前,已经占据了服务端市场的极大占有量。
但是,弱类型,一些方便的特性由于新手程序员的不当使用,造成了一些漏洞,这篇文章就来介绍一下一些渗透中可以用的特性。
上面都是废话,下面我们进入正题
1.弱类型的比较==导致的漏洞
注:这些漏洞适用于所有版本的php
先来复习一下基本的语法:php中有如下两种比较符号:两个等号和三个等号(这一点和Javascript)有些类似
$a==$b
$a===$b
我们来一下php官方手册的说法
$a == $b
等于 TRUE,如果类型转换后 $a 等于 $b。$a === $b
全等 TRUE,如果 $a 等于 $b,并且它们的类型也相同。
明确的看到,两个等于号的等于会在比较的时候进行类型转换的比较。
如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。此规则也适用于 switch 语句。当用 === 或 !== 进行比较时则不进行类型转换,因为此时类型和数值都要比对.
明确的写出了 如果一个数值和一个字符串比较,那么会将字符串转换为数值(而不是相反,将数值转化为字符串)
然而,php是如何将一个字符串转化为数值的呢,我们继续查看php手册
当一个字符串被当作一个数值来取值,其结果和类型如下:如果该字符串没有包含 ‘.’,’e’ 或 ‘E’ 并且其数字值在整型的范围之内(由 PHP_INT_MAX 所定义),该字符串将被当成 integer 来取值。其它所有情况下都被作为 float 来取值。该字符串的开始部分决定了它的值。如果该字符串以合法的数值开始,则使用该数值。否则其值为 0(零)。合法数值由可选的正负号,后面跟着一个或多个数字(可能有小数点),再跟着可选的指数部分。指数部分由 ‘e’ 或 ‘E’ 后面跟着一个或多个数字构成。
这是官方手册上面的几个例子
<?php
$foo = 1 + "10.5"; // $foo is float (11.5)
$foo = 1 + "-1.3e3"; // $foo is float (-1299)
$foo = 1 + "bob-1.3e3"; // $foo is integer (1)
$foo = 1 + "bob3"; // $foo is integer (1)
$foo = 1 + "10 Small Pigs"; // $foo is integer (11)
$foo = 4 + "10.2 Little Piggies"; // $foo is float (14.2)
$foo = "10.0 pigs " + 1; // $foo is float (11)
$foo = "10.0 pigs " + 1.0; // $foo is float (11)
?>
我们大概可以总结出如下的规则:当一个字符串被转换为数值时
- 如果一个字符串为 “合法数字+e+合法数字”类型,将会解释为科学计数法的浮点数
- 如果一个字符串为 “合法数字+ 不可解释为合法数字的字符串”类型,将会被转换为该合法数字的值,后面的字符串将会被丢弃
如果一个字符串为“不可解释为合法数字的字符串+任意”类型,则被转换为0! 为0…为0
<?php
'a'==0 // true
'12a'==12 //true
'1'==1 //true
'1aaaa55sss66'==1 //true
当然,上面的那些等式对于===都是false的,原本一些应该用===的地方误用了==,导致了可以注入的地方。
示例代码 1:利用转为数字后相等的漏洞
<?php
if (isset($_GET['v1']) && isset($_GET['v2'])) {
$logined = true;
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
if (!ctype_alpha($v1)) {$logined = false;}
if (!is_numeric($v2) ) {$logined = false;}
if (md5($v1) != md5($v2)) {$logined = false;}
if ($logined){
// continuue to do other things
} else {
echo "login failed"
}
}
?
这是一个ctf的题目,非常有趣,可以看到,要求给出两字符串,一个是纯数字型,一个只能出现字符,使两个的md5哈希值相等,然而这种强碰撞在密码学上都是无法做到的。
但是我们看到,最终比较两者的哈希的时候,使用的是等于 而不是 全等于 ,因此可以利用一下这个漏洞
再回头看一 md5()
函数
string md5 ( string $str [, bool $raw_output = false ] )
str原始字符串。raw_output如果可选的 raw_output 被设置为 TRUE,那么 MD5 报文摘要将以16字节长度的原始二进制格式返回。
可以知道,第二个参数为true的时候,显示16位的结果,而为false和没有第二个参数时,为32位的16进制码(16位的结果是把32位的作为ASCII码进行解析)
16进制的数据中是含有e的,可以构建使得两个数字比较的,这里有一个现成的例子:
md5('240610708')
//0e462097431906509019562988736854.
md5('QNKCDZO')
//0e830400451993494058024219903391
可以看到,这两个字符串一个只包含数字,一个只包含字母,虽然两个的哈希不一样,但是都是一个形式:0e 纯数字这种格式的字符串在判断相等的时候会被认为是科学计数法的数字,先做字符串到数字的转换。
转换后都成为了0的好多好多次方,都是0,相等。(大家可以自己尝试一下)因此
md5('240610708')==md5('QNKCDZO'); //True
md5('240610708')===md5('QNKCDZO'); //False
用===可以避免这一漏洞。
示例代码2: 利用 类’a'==0的漏洞
<?php
if (isset($_POST['json'])) {
$json = json_decode($_POST['json']);
$key ="**********************";
if ($json->key == $key) {
//login success ,continue
} else {
//login failed ,return
}
?>
这次这个例子是传入一个JSON的数据,JSON在RESTful的网站中是很常用的一种数据传输的格式。这个表单会把一个name为key的input的数据作为json传到服务端
{"key":"your input"}
我们该如何破解?想”a”==0这个漏洞,之用我们使$json->key
是一个数字类型的变量就可以,怎么做到呢?
php的json_decode()
函数会根据json数据中的数据类型来将其转换为php中的相应类型的数据,也就是说,如果我们在json中传一个string类型,那么该变量就是string,如果传入的是number,则该变量为number。因此,我们如果传入一个数字,就可以使之相等。网页中的表单可能限制了所有的输入都是string,即使输入数字,传入的东西也是
{"key":"0"}
这是一个字符串0,我们需要让他为数字类型,用burp拦截,把两个双引号去掉,变成这样:
{"key":0}
即可。
值得讨论的一点是,在这种方法的漏洞利用中,很难在直接表单类型的POST的数据中使用,这是为什么呢,这个和HTTP协议有关。首先,我们看一下,在POST给服务器的数据中,有几种类型,也就是HTTP header中的Content-Type:
application/x-www-form-urlencoded
multipart/form-data
application/json
application/xml
第一个application/x-www-form-urlencoded,是一般表单形式提交的content-type第二个,是包含文件的表单。第三,四个,分别是json和xml,一般是js当中上传的.
但是因为在直接的POST的payload当中是无法区分字符串和数字的,因为在其中并没有引号出现,举一个抓包的例子
POST /login HTTP/1.1
Host: xxx.com
Content-Length: 41
Accept: application/json, text/javascript,application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Connection: close
username=admin&password=admin
可以看到,payload是放在http包的最后面的,而且都是以没有引号的形式传递的,并没有办法区分到底是字符串还是数字。因此,PHP将POST的数据全部保存为字符串形式,也就没有办法注入数字类型的数据了而JSON则不一样,JSON本身是一个完整的字符串,经过解析之后可能有字符串,数字,布尔等多种类型。
2. strcmp漏洞
注:这一个漏洞适用与5.3之前版本的php
我们首先看一下这个函数,这个函数是用于比较字符串的函数
int strcmp ( string $str1 , string $str2 )
参数 str1第一个字符串。str2第二个字符串。如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
可知,传入的期望类型是字符串类型的数据,但是如果我们传入非字符串类型的数据的时候,这个函数将会有怎么样的行为呢?实际上,当这个函数接受到了不符合的类型,这个函数将发生错误,但是在5.3之前的php中,显示了报错的警告信息后,将return 0 !!!! 也就是虽然报了错,但却判定其相等了。这对于使用这个函数来做选择语句中的判断的代码来说简直是一个致命的漏洞,当然,php官方在后面的版本中修复了这个漏洞,使得报错的时候函数不返回任何值。但是我们仍然可以使用这个漏洞对使用老版本php的网站进行渗透测试。看一段示例代码:
<?php
$password="***************"
if(isset($_POST['password'])){
if (strcmp($_POST['password'], $password) == 0) {
echo "Right!!!login success";n
exit();
} else {
echo "Wrong password..";
}
?>
对于这段代码,我们能用什么办法绕过验证呢, 只要我们$_POST['password']
是一个数组或者一个object即可,但是上一个问题的时候说到过,只能上传字符串类型,那我们又该如何做呢。
其实php为了可以上传一个数组,会把结尾带一对中括号的变量,例如 xxx[]
的name(就是$_POST中的key),当作一个名字为xxx
的数组构造类似如下的request
POST /login HTTP/1.1
Host: xxx.com
Content-Length: 41
Accept: application/json, text/javascript
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.59 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Connection: close
password[]=admin
即可使得上述代码绕过验证成功。
3 总结
这一类型的漏洞的特点主要就是利用PHP中 的类型特性来绕过验证。由于 == 和 === 有着明显的区分,因此,估计短期内PHP的作者并不会调整对于这两个符号的策略。而对于开发市场而言,随着培训机构的增多,后端程序员尤其是php后端程序员的门槛越来越低,其水平必定也是良莠不齐,这些二把刀程序员可能带来更多的此类对于特性的不当使用导致的漏洞,因此这类漏洞仍然是非常具有利用价值的。
总结一下,对于开发人员,需要坚持几个习惯:
- 认真阅读PHP manual,不能以其他语言的经验来完全带入php进行编码
- 在使用一个运算符或者函数之前,详细的查看文档,搞清楚函数在什么样的条件下,会有怎样的行为。
记住保证安全的几句箴言:任何用户输入都是不可信的!对于web应用来说,前端(浏览器端)的安全限制只能起到防止一般用户的误输入行为,完全不可能对于黑帽子的行为有任何的防御作用
因此,在防御这个漏洞的过程中,保证几件事情:
- 在所有可能的地方,都使用
===
来代替==
- 对于用户输入做过滤和类型检查
- 尽量使用新版本的php,apache
基本上就可以完美的防御这一类的漏洞。
而对于渗透测试人员,在代码审计的过程中,对于有==
,strcmp
的比较也应极为敏感 。在黑盒渗透的时候也可以对于代码进行猜测,结合信息搜集过程中的一些版本特性,利用这些漏洞来绕过验证。
PHP网站渗透中的奇技淫巧:检查相等时的漏洞的更多相关文章
- PHP渗透中的奇淫技巧--检查相等时的漏洞
PHP是现在网站中最为常用的后端语言之一,是一种类型系统 动态.弱类型的面向对象式编程语言.可以嵌入HTML文本中,是目前最流行的web后端语言之一,并且可以和Web Server 如apache和n ...
- Emacs中的拼写检查
无论是在Emacs中写英文日记(diary).Org mode笔记,还是撰写程序的注释和文档,拼写检查都是一项提高工作效率.保证成果品质的必不可缺的工具.拼写检查对于常见的文字处理软件(如Word.L ...
- 网站开发中很实用的 HTML5 & jQuery 插件
这篇文章挑选了15款在网站开发中很实用的 HTML5 & jQuery 插件,如果你正在寻找能优化网站,使其更具创造力和视觉冲击,那么本文正是你需要的.这些优秀的 jQuery 插件能为你的网 ...
- 网站建设中前端常用的jQuery+easing缓动的动画
网站建设中前端人员利用jQuery实现动画再简单不过了,只是要实现更酷的效果还需要插件来帮忙,easing就是一款帮助jQuery实现缓动动画的插件,经过试用,效果很不错! 下载该插件:jquery. ...
- 内网渗透中的反弹Shell与端口转发
from:https://www.91ri.org/9367.html Web渗透中的反弹Shell与端口转发 php需未禁用exec函数一:生成php反弹脚本msf > msfpayload ...
- QA在网站建设中的作用
在网站建设项目中,有一个团队负责产品测试并识别产品中的缺陷是很有意义的.问题在于,不应该只依赖这个团队来发现所有的缺陷,就像航空公司不能只依靠空乘人员确保飞机安全一样.这个观点的核心是一个简单的事实, ...
- SharePoint 2013 网站定义中添加页面布局
今天在Visual Studio 2012中将页面布局打包到网站定义中. 新建Module “MasterPageGallary” 在Element中如下: <Elements xmlns=&q ...
- 整合Spring.net到asp.net网站开发中初探
整合Spring.net到asp.net网站开发中初探 http://www.veryhuo.com 2009-10-21 烈火网 投递稿件 我有话说 Spring提供了一个轻量级的用于构建企业级 ...
- 我在网站开发中经常用到的几个js函数01
这是我在最近的一个网站项目中频繁用到的几个js函数,非常实用.包括:1.js获取地址栏参数:2.返回cookies字符串中指定键对应的值:3.json格式的日期转换为正常格式4.清除cookie. / ...
随机推荐
- 【数位dp】bzoj3209: 花神的数论题
Description 背景众所周知,花神多年来凭借无边的神力狂虐各大 OJ.OI.CF.TC …… 当然也包括 CH 啦.描述话说花神这天又来讲课了.课后照例有超级难的神题啦…… 我等蒟蒻又遭殃了. ...
- js的弹性运动
弹性: 速度+=(目标点-当前值)/系数://系数大概可以选择6,7,8 速度*=摩擦系数://系数可以选择0.7,0.75,0.8 缓冲: 速度=(目标点-当前值)/系数: 速度取整:
- C语言之结构体、联合体
结构体 1,结构体即为多个基本数据类型组合而成的数据类型.结构体本质上同int等一样同为数据类型,可以定义变量,内部成员不能直接赋值. struct Man { ; ; }; 上面是错误的.正确写法 ...
- Linux中的定时任务简单操作实例
今天,我怀着一颗感恩的心,写了一个小小的定时任务,细想还是写个简单的例子吧,希望能帮到你! 首先我在/usr/local/文件夹下创建了一个文件,hah.sh文件 在hah.sh里面编写shell脚本 ...
- Web框架之Django_05 模型层了解(单表查询、多表查询、聚合查询、分组查询)
摘要: 单表查询 多表查询 聚合查询 分组查询 一.Django ORM 常用字段和参数: 常用字段:#AutoFieldint自增列,必须填入参数primary_key = True,当model中 ...
- cocos2d-x游戏开发(一)之环境搭建篇
前言 进入研究生生涯已经有一段时间,感觉却没做些什么,实验室虽有一个很大的国家项目,但考虑到它这么的单一,总想利用业余时间做些什么,拓宽一下自己的知识面. 偶然机会,了解到cocos这个东东,恰好,实 ...
- CSS 如何让 height:100%; 起作用
当你设置一个页面元素的高度(height)为100%时,期望这样元素能撑满整个浏览器窗口的高度,但大多数情况下,这样的做法没有任何效果.你知道为什么height:100%不起作用吗? 按常理,当我们用 ...
- TOJ 2710: 过河 路径压缩
2710: 过河 Time Limit(Common/Java):1000MS/10000MS Memory Limit:65536KByteTotal Submit: 32 ...
- MySQL主从复制报错一致性问题解决
当MySQL主从复制中因为不一致报错的情况,我们第一时间想到的就是使用pt-table-checksum来进行检查主从一致并进行修复,但是使用此工具的前提是主从复制线程都为on状态, 所以这种情况下可 ...
- TCP内核参数
tcp_syn_retries :INTEGER默认值是5对于一个新建连接,内核要发送多少个 SYN 连接请求才决定放弃.不应该大于255,默认值是5,对应于180秒左右时间.(对于大负载而物理通信良 ...