由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分页显示制作详细讲解
Oct 09 PHP
解决phpmyadmin中文乱码问题。。。
Jan 18 PHP
php将gd生成的图片缓存到memcache的小例子
Jun 05 PHP
PHP编码规范的深入探讨
Jun 06 PHP
深入PHP数据加密详解
Jun 18 PHP
codeigniter集成ucenter1.6双向通信的解决办法
Jun 12 PHP
php实现计数器方法小结
Jan 05 PHP
深入php内核之php in array
Nov 10 PHP
PHP开发中常用的十个代码样例
Feb 02 PHP
PHP Try-catch 语句使用技巧
Feb 28 PHP
php实现批量修改文件名称的方法
Jul 23 PHP
PDO的安全处理与事物处理方法
Oct 31 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
Thinkphp中数据按分类嵌套循环实现方法
2014/10/30 PHP
php foreach如何跳出两层循环(详解)
2016/11/05 PHP
php array_values 返回数组的值实例详解
2016/11/17 PHP
PHP实现字母数字混合验证码功能
2019/07/11 PHP
php+mysql实现的无限分类方法类定义与使用示例
2020/05/27 PHP
css动画效果之animation的常用样式
2021/03/09 HTML / CSS
JavaScript this调用规则说明
2010/03/08 Javascript
字符串的replace方法应用浅析
2011/12/06 Javascript
JavaScript 高级篇之函数 (四)
2012/04/07 Javascript
理解javascript中的回调函数(callback)
2014/09/02 Javascript
iPhone手机上搭建nodejs服务器步骤方法
2015/07/06 NodeJs
jQuery的框架介绍
2016/05/11 Javascript
js事件驱动机制 浏览器兼容处理方法
2016/07/23 Javascript
微信小程序 获取相册照片实例详解
2016/11/16 Javascript
详解springmvc 接收json对象的两种方式
2016/12/06 Javascript
如何使用JS在HTML中自定义字符串格式化
2017/07/20 Javascript
vue.js提交按钮时进行简单的if判断表达式详解
2018/08/08 Javascript
vuex存储复杂参数(如对象数组等)刷新数据丢失的解决方法
2019/11/05 Javascript
微信小程序实现菜单左右联动
2020/05/19 Javascript
解决VUE自定义拖拽指令时 onmouseup 与 click事件冲突问题
2020/07/24 Javascript
JavaScript实现4位随机验证码的生成
2021/01/28 Javascript
[07:03]显微镜下的DOTA2第九期——430圣堂刺客杀戮秀
2014/06/20 DOTA
python检测远程udp端口是否打开的方法
2015/03/14 Python
Win7下Python与Tensorflow-CPU版开发环境的安装与配置过程
2018/01/04 Python
python中如何设置代码自动提示
2020/07/15 Python
详解HTML5中的manifest缓存使用
2015/09/09 HTML / CSS
简历中求职的个人自我评价
2013/12/03 职场文书
感恩的演讲稿
2014/05/06 职场文书
综合实践活动报告
2015/02/05 职场文书
争先创优个人总结
2015/03/04 职场文书
自我检讨书怎么写
2015/05/07 职场文书
文明礼仪主题班会
2015/08/13 职场文书
周一问候语大全
2015/11/10 职场文书
5种方法告诉你如何使JavaScript 代码库更干净
2021/09/15 Javascript
【DOTA2】当街暴打?PSG LGD vs VG - DPC 2022 WINTER TOUR CN
2022/04/02 DOTA
大脑的记忆过程在做数据压缩,不同图形也有共同的记忆格式
2022/04/29 数码科技