由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通过COM使用ADODB的简单例子
Dec 31 PHP
用php实现像JSP,ASP里Application那样的全局变量
Jan 12 PHP
php目录操作函数之获取目录与文件的类型
Dec 29 PHP
说说PHP的autoLoad自动加载机制
Sep 27 PHP
排序算法之PHP版快速排序、冒泡排序
Apr 09 PHP
ThinkPHP实现带验证码的文件上传功能实例
Nov 01 PHP
php简单定时执行任务的实现方法
Feb 23 PHP
php截取指定2个字符之间字符串的方法
Apr 15 PHP
关于php 高并发解决的一点思路
Apr 16 PHP
Thinkphp结合AJAX长轮询实现PC与APP推送详解
Jul 31 PHP
PHP高精确度运算BC函数库实例详解
Aug 15 PHP
CodeIgniter整合Smarty的方法详解
Aug 25 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
如何限制访问者的ip(PHPBB的代码)
2006/10/09 PHP
PHP 将逗号、空格、回车分隔的字符串转换为数组的函数
2012/06/07 PHP
PHP移动文件指针ftell()、fseek()、rewind()函数总结
2014/11/18 PHP
PHP获取文件行数的方法
2015/06/10 PHP
基于ThinkPHP删除目录及目录文件函数
2020/10/28 PHP
Jquery中获取iframe的代码
2011/01/11 Javascript
js获取某元素的class里面的css属性值代码
2014/01/16 Javascript
JsRender for index循环索引用法详解
2014/10/31 Javascript
使用javascript将时间转换成今天,昨天,前天等格式
2015/06/25 Javascript
jquery+ajax实现注册实时验证实例详解
2015/12/08 Javascript
使用postMesssage()实现跨域iframe页面间的信息传递方法
2016/03/29 Javascript
关于数据与后端进行交流匹配(点亮星星)
2016/08/03 Javascript
JavaScript正则替换HTML标签功能示例
2017/03/02 Javascript
angular.JS实现网页禁用调试、复制和剪切
2017/03/31 Javascript
简单实现JS上传图片预览功能
2017/04/14 Javascript
angularjs 缓存的使用详解
2018/03/19 Javascript
vue实现选项卡及选项卡切换效果
2018/04/24 Javascript
使用vue-cli创建项目的图文教程(新手入门篇)
2018/05/02 Javascript
详解create-react-app 自定义 eslint 配置
2018/06/07 Javascript
Vue项目数据动态过滤实践及实现思路
2018/09/11 Javascript
小程序组件之自定义顶部导航实例
2019/06/12 Javascript
微信小程序npm引入vant-weapp的踩坑记录
2019/08/01 Javascript
微信小程序开发之map地图组件定位并手动修改位置偏差
2019/08/17 Javascript
React Native登录之指纹登录篇的示例代码
2020/11/03 Javascript
[02:08]2018年度CS GO枪械皮肤设计大赛优秀作者-完美盛典
2018/12/16 DOTA
Python中实现远程调用(RPC、RMI)简单例子
2014/04/28 Python
Python把csv数据写入list和字典类型的变量脚本方法
2018/06/15 Python
Python基于xlrd模块操作Excel的方法示例
2018/06/21 Python
Python高级编程之消息队列(Queue)与进程池(Pool)实例详解
2019/11/01 Python
python opencv 实现对图像边缘扩充
2020/01/19 Python
python 字典item与iteritems的区别详解
2020/04/25 Python
《我的信念》教学反思
2014/02/15 职场文书
信息与计算科学专业推荐信
2014/02/23 职场文书
大学军训决心书
2015/02/05 职场文书
优质服务标语口号
2015/12/26 职场文书
MYSQL 的10大经典优化案例场景实战
2021/09/14 MySQL