由php中字符offset特征造成的绕过漏洞详解


Posted in PHP onJuly 07, 2017

php中的字符offset特性

php中的字符串存在一个非常有趣的特性,php中的字符串也可以像数组一样进行取值。

$test = "hello world";
echo $test[0];

最后的结果就是h。

但是上述的这种特性有时会有意想不到的效果,看下面这段代码

$mystr = "hello world";
echo $mystr["pass"];

上述的代码的输出结果是h.这是为什么呢?其实很简单,和很多其他的语言一样,字符串在php中也像数组一样可以使用下标取值。$mystr["pass"]中pass会被进行隐性类型转换为0,这样$mystr[0]的输出结果就是首字母h.
同样地,如果尝试如下的代码:

$mystr = "hello world";
echo $mystr["1pass"];

输出结果就是e.因为1pass会被隐性类型转换为1,$mystr[1]的输出结果就是第二个字母e.

字符特性造成的漏洞

下面这段代码是在在phpspy2006中用于判断登录时所使用的代码。

$admin['check'] = "1";
$admin['pass'] = "angel";
......
if($admin['check'] == "1") {
....
}

这样的验证逻辑如果利用上述的特性就很容易地就可以被绕过。$admin没有被初始定义为数组类型,那么当我们用字符串提交时phpsyp.php?admin=1abc时,php会取字符串1xxx的第一位,成功绕过if的条件判断。

上面那段代码是一个代码片段,接下来的这段代码是一段完整的逻辑代码,来自于php4fun中第5题,比较有意思。

<?php
# GOAL: overwrite password for admin (id=1)
#  Try to login as admin
# $yourInfo=array( //this is your user data in the db
# 'id' => 8,
# 'name' => 'jimbo18714',
# 'pass' => 'MAYBECHANGED',
# 'level' => 1
# );
require 'db.inc.php';

function mres($str)
{
 return mysql_real_escape_string($str);
}

$userInfo = @unserialize($_GET['userInfo']);

$query = 'SELECT * FROM users WHERE id = \'' . mres($userInfo['id']) . '\' AND pass = \'' . mres($userInfo['pass']) . '\';';

$result = mysql_query($query);
if (!$result || mysql_num_rows($result) < 1) {
 die('Invalid password!');
}

$row = mysql_fetch_assoc($result);
foreach ($row as $key => $value) {
 $userInfo[$key] = $value;
}

$oldPass = @$_GET['oldPass'];
$newPass = @$_GET['newPass'];
if ($oldPass == $userInfo['pass']) {
 $userInfo['pass'] = $newPass;
 $query = 'UPDATE users SET pass = \'' . mres($newPass) . '\' WHERE id = \'' . mres($userInfo['id']) . '\';';
 mysql_query($query);
 echo 'Password Changed.';
} else {
 echo 'Invalid old password entered.';
}

这道题目网上也仅仅只是给了一个最终的答案,其中的原理都没有说或者没有说得很详细。其实原理就是上面讲到的php的字符特性。

题目要求很简单就是修改admin的密码,admin的id为1。我们需要思考以下几个问题:

  • 如何在更新的时候将id修改为1
  • $userInfo['pass'] = $newPass;这行代码有什么作用,为什么会在if判断语句中存在这种的代码

想通了这两个问题,那么最终的解决方法也有了。将id为8的用户的密码修改为8,然后传入一个userInfo的字符串‘8',突破查询防护,最后利用$userInfo['pass'] = $newPass将id修改为1。

最终的payload就是;

第一次提交, index.php?userInfo=a:2:{s:2:"id";i:8;s:4:"pass";s:12:"MAYBECHANGED";}&oldPass=MAYBECHANGED&newPass=8,目的是将id为8的用户的密码修改为8

第二次提交,index.php?userInfo=s:1:"8";&oldPass=8&newPass=1,这样序列化$userInfo得到的就是字符串‘8',即$userInfo = ‘8' ,这样数据库查询验证就可以通过。之后的if验证也可以通过,通过这行代码$userInfo['pass'] = $newPass;,由于$newpass的值为1,那么上述代码变为了$userInfo['pass'] = 1; ,$userInfo由于一个字符串类型,最后得到的是$userInfo='1' ,最后就可以更新id为1的用户的密码了。

修复方式

这种漏洞的修复方式也很简单,事先定义好数据类型同时在使用时最好检查一下所使用的数据类型是否和预期的一致。否则就会出现上述的绕过的问题。同时要控制好输入,对输入的数据要进行检查不要随意地使用。

参考

https://github.com/80vul/webzine/blob/master/webzine_0x06/PSTZine_0x06_0x03.txt

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
PHP 远程文件管理,可以给表格排序,遍历目录,时间排序
Aug 07 PHP
ajax完美实现两个网页 分页功能的实例代码
Apr 16 PHP
在yii中新增一个用户验证的方法详解
Jun 20 PHP
php计算几分钟前、几小时前、几天前的几个函数、类分享
Apr 09 PHP
php实现获取文章内容第一张图片的方法
Nov 04 PHP
php字符串分割函数用法实例
Mar 17 PHP
php快速排序原理与实现方法分析
May 26 PHP
Yii中CGridView禁止列排序的设置方法
Jul 12 PHP
PHP 类与构造函数解析
Feb 06 PHP
YII中Ueditor富文本编辑器文件和图片上传的配置图文教程
Mar 15 PHP
ThinkPHP模板标签eq if 中区分0,null,false的方法
Mar 24 PHP
PHP实现唤起微信支付功能
Feb 18 PHP
Laravel使用PHPQRCODE实现生成带有LOGO的二维码图片功能示例
Jul 07 #PHP
thinkPHP微信分享接口JSSDK用法实例
Jul 07 #PHP
微信开发之获取JSAPI TICKET
Jul 07 #PHP
Yii2第三方类库插件Imagine的安装和使用
Jul 06 #PHP
一个实用的php验证码类
Jul 06 #PHP
万能的php分页类
Jul 06 #PHP
PHP 实现从数据库导出到.csv文件方法
Jul 06 #PHP
You might like
JQuery实现自定义对话框的代码
2008/06/15 Javascript
Javascript和Java获取各种form表单信息的简单实例
2014/02/14 Javascript
js函数参数设置默认值的一种变通实现方法
2014/05/26 Javascript
js实现精美的银灰色竖排折叠菜单
2015/05/16 Javascript
JavaScript检测并限制复选框选中个数的方法
2015/08/12 Javascript
七个不允许错过的jQuery小技巧
2015/12/21 Javascript
AngularJs 60分钟入门基础教程
2016/04/03 Javascript
JavaScript函数节流概念与用法实例详解
2016/06/20 Javascript
利用Angularjs和Bootstrap前端开发案例实战
2016/08/27 Javascript
JS封装通过className获取元素的函数示例
2016/12/20 Javascript
jQuery插件FusionCharts绘制2D柱状图和折线图的组合图效果示例【附demo源码】
2017/04/10 jQuery
浅谈JS对html标签的属性的干预以及对CSS样式表属性的干预
2017/06/25 Javascript
vue获取input输入值的问题解决办法
2017/10/17 Javascript
解决option标签selected=&quot;selected&quot;属性失效的问题
2017/11/06 Javascript
基于jQuery实现Ajax验证用户名是否可用实例
2018/03/25 jQuery
vue3.0 CLI - 2.3 - 组件 home.vue 中学习指令和绑定
2018/09/14 Javascript
微信小程序网络层封装的实现(promise, 登录锁)
2019/05/08 Javascript
解决Layui中templet中a的onclick参数传递的问题
2019/09/20 Javascript
jQuery实现飞机大战小游戏
2020/07/05 jQuery
python文件和目录操作方法大全(含实例)
2014/03/12 Python
python简单判断序列是否为空的方法
2015/06/30 Python
Python排序算法之选择排序定义与用法示例
2018/04/29 Python
python实现创建新列表和新字典,并使元素及键值对全部变成小写
2019/01/15 Python
详解Django中CBV(Class Base Views)模型源码分析
2019/02/25 Python
Python如何实现强制数据类型转换
2019/11/22 Python
解决Django中checkbox复选框的传值问题
2020/03/31 Python
Python3.7 读取音频根据文件名生成脚本的代码
2020/04/07 Python
Django自带的用户验证系统实现
2020/12/18 Python
python爬虫爬取图片的简单代码
2021/01/18 Python
python 自动识别并连接串口的实现
2021/01/19 Python
css3隔行变换色实现示例
2014/02/19 HTML / CSS
向领导表决心的话
2014/03/11 职场文书
潘婷洗发水广告词
2014/03/14 职场文书
送达通知书
2015/04/25 职场文书
天那边观后感
2015/06/09 职场文书
浅谈node.js中间件有哪些类型
2021/04/29 Javascript