由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开发入门教程之面向对象
Dec 05 PHP
php登陆页的密码处理方式分享
Oct 14 PHP
PHP错误Warning: Cannot modify header information - headers already sent by解决方法
Sep 27 PHP
PHP 验证登陆类分享
Mar 13 PHP
YII2.0之Activeform表单组件用法实例
Jan 09 PHP
phplist及phpmailer(组合使用)通过gmail发送邮件的配置方法
Mar 30 PHP
php HTML无刷新提交表单
Apr 05 PHP
php简单的上传类分享
May 15 PHP
PHP sleep()函数, usleep()函数
Aug 25 PHP
PHP基于MySQLI函数封装的数据库连接工具类【定义与用法】
Aug 11 PHP
ThinkPHP整合datatables实现服务端分页的示例代码
Feb 10 PHP
php使用lua+redis实现限流,计数器模式,令牌桶模式
Apr 04 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
3种平台下安装php4经验点滴
2006/10/09 PHP
php将图片保存入mysql数据库失败的解决方法
2014/12/27 PHP
js setTimeout()函数介绍及应用以倒计时为例
2013/12/12 Javascript
纯js实现无限空间大小的本地存储
2015/06/18 Javascript
jquery实现LED广告牌旋转系统图片切换效果代码分享
2015/08/26 Javascript
jQuery的实例及必知重要的jQuery选择器详解
2016/05/20 Javascript
js实现String.Fomat的实例代码
2016/09/02 Javascript
浅谈js继承的实现及公有、私有、静态方法的书写
2016/10/28 Javascript
JS实现线性表的顺序表示方法示例【经典数据结构】
2017/04/11 Javascript
jQuery插件artDialog.js使用与关闭方法示例
2017/10/09 jQuery
Angular angular-file-upload文件上传的示例代码
2018/08/23 Javascript
vue权限管理系统的实现代码
2019/01/17 Javascript
ES6 如何改变JS内置行为的代理与反射
2019/02/11 Javascript
微信小程序如何使用canvas二维码保存至手机相册
2019/07/15 Javascript
详解JSON.stringify()的5个秘密特性
2020/05/26 Javascript
JavaScript类的继承多种实现方法
2020/05/30 Javascript
js实现贪吃蛇小游戏(加墙)
2020/07/31 Javascript
javascript实现放大镜功能
2020/12/09 Javascript
vue项目配置 webpack-obfuscator 进行代码加密混淆的实现
2021/02/26 Vue.js
Python time模块详解(常用函数实例讲解,非常好)
2014/04/24 Python
Python3使用PyQt5制作简单的画板/手写板实例
2017/10/19 Python
TensorFlow saver指定变量的存取
2018/03/10 Python
详解Python list和numpy array的存储和读取方法
2019/11/06 Python
Python Excel vlookup函数实现过程解析
2020/06/22 Python
html5中的input新属性range使用记录
2014/09/05 HTML / CSS
比利时家具购买网站:Home24
2019/01/03 全球购物
莫斯科购买书籍网站:Book24
2020/01/12 全球购物
马来西亚排名第一的宠物用品店:Pets Wonderland
2020/04/16 全球购物
L’Artisan Parfumeur官网:法国香水品牌
2020/08/11 全球购物
教你怎样写好自我评价
2013/10/05 职场文书
大学生实习自我鉴定
2013/12/11 职场文书
大学系主任推荐信范文
2013/12/24 职场文书
2014年应届大学生毕业自我鉴定
2014/01/31 职场文书
放飞中国梦演讲稿
2014/04/23 职场文书
爱耳日活动总结
2014/04/30 职场文书
2014年银行工作总结范文
2014/11/12 职场文书