如何对PHP程序中的常见漏洞进行攻击(下)


Posted in PHP onOctober 09, 2006

如何对PHP程序中的常见漏洞进行攻击(下)
翻译:analysist(分析家)
来源:http://www.china4lert.org

如何对PHP程序中的常见漏洞进行攻击(下)

原著:Shaun Clowes <http://www.securereality.com.au/>
翻译:analysist <http://www.nsfocus.com/>

[库文件]
正如我们前面讨论的那样,include()和require()主要是为了支持代码库,因为我们一般是把一些经常使用的函数放到一个独立的文件中,这个独立的文件就是代码库,当需要使用其中的函数时,我们只要把这个代码库包含到当前的文件中就可以了。

最初,人们开发和发布PHP程序的时候,为了区别代码库和主程序代码,一般是为代码库文件设置一个“.inc”的扩展名,但是他们很快发现这是一个错误,因为这样的文件无法被PHP解释器正确解析为PHP代码。如果我们直接请求服务器上的这种文件时,我们就会得到该文件的源代码,这是因为当把PHP作为Apache的模块使用时,PHP解释器是根据文件的扩展名来决定是否解析为PHP代码的。扩展名是站点管理员指定的,一般是“.php”, “.php3”和“.php4”。如果重要的配置数据被包含在没有合适的扩展名的PHP文件中,那么远程攻击者很容易得到这些信息。

最简单的解决方法就是给每个文件都指定一个PHP文件的扩展名,这样可以很好的防止泄露源代码的问题,但是又产生了新的问题,通过请求这个文件,攻击者可能使本该在上下文环境中运行的代码独立运行,这可能导致前面讨论的全部攻击。

下面是一个很明显的例子:

In main.php:
<?php
  $libDir = "/libdir";
  $langDir = "$libdir/languages";

  ...

  include("$libdir/loadlanguage.php":
?>

In libdir/loadlanguage.php:
<?php
  ...

  include("$langDir/$userLang");
?>

当“libdir/loadlanguage.php”被“main.php”调用时是相当安全的,但是因为“libdir/loadlanguage”具有“.php”的扩展名,因此远程攻击者可以直接请求这个文件,并且可以任意指定“$langDir”和“$userLang”的值。
[Session文件]
PHP 4或更新的版本提供了对sessions的支持,它的主要作用是在PHP程序中保存页与页之间的状态信息。例如,当一个用户登陆进入网站,他登陆了这个事实以及谁登陆进入这个网站都被保存在session中,当他在网站中到处浏览时,所有的PHP代码都可以获得这些状态信息。

事实上,当一个session启动时(实际上是在配置文件中设置为在第一次请求时自动启动),就会生成一个随机的“session id”,如果远程浏览器总是在发送请求时提交这个“session id”的话,session就会一直保持。这通过Cookie很容易实现,也可以通过在每页提交一个表单变量(包含“session id”)来实现。PHP程序可以用session注册一个特殊的变量,它的值会在每个PHP脚本结束后存在session文件中,也会在每个PHP脚本开始前加载到变量中。下面是一个简单的例子:

<?php
  session_destroy(); // Kill any data currently in the session
  $session_auth = "shaun";
  session_register("session_auth"); // Register $session_auth as a session variable
?>

新版本的PHP都会自动把“$session_auth”的值设置为“shaun”,如果它们被修改的话,以后的脚本都会自动接受修改后的值,这对无状态的Web来说的确是种很不错的工具,但是我们也应该小心。

一个很明显的问题就是确保变量的确来自session,例如,给定上面的代码,如果后续的脚本是下面这样的话:

<?php
  if (!empty($session_auth))
   // Grant access to site here
?>

上面的代码假定如果“$session_auth”被置位的话,就是从session,而不是从用户输入来置位的,如果攻击者通过表单输入来置位的话,他就可以获得对站点的访问权。注意攻击者必须在session注册该变量之前使用这种攻击方法,一旦变量被放进了session,就会覆盖任何表单输入。

Session数据一般是保存在文件中(位置是可配置的,一般是“/tmp”),文件名一般是类似“sess_<session id>”的形式,这个文件包含变量名称,变量类型,变量值和一些其它的数据。在多主机系统中,因为文件是以运行Web服务器的用户身份(一般是nobody)保存的,因此恶意的站点拥有者就可以通过创建一个session文件来获得对其它站点的访问,甚至可以检查session文件中的敏感信息。

Session机制也为攻击者把自己的输入保存在远程系统的文件中提供了另一个方便的地方,对于上面的例子来说,攻击者需要在远程系统放置一个包含PHP代码的文件,如果不能利用文件上载做到的话,他通常会利用session为一个变量按照自己的意愿赋一个值,然后猜测session文件的位置,而他知道文件名是“php<session id>”,所以只需猜测目录,而目录一般就是“/tmp”。

另外,攻击者可以任意指定“session id”(例如“hello”),然后用这个“session id”创建一个session文件(例如“/tmp/sess_hello”),但是“session id”只能是字母和数字组合。

[数据类型]
PHP具有比较松散的数据类型,变量的类型依赖于它们所处的上下文环境。例如:“$hello”开始是字符串变量,值为“”,但是在求值时,就变成了整形变量“0”,这有时可能会导致一些意想不到的结果。如果“$hello”的值为“000”还是为“0”是不同的,empty()返回的结果也不会为真。

PHP中的数组是关联数组,也就是说,数组的索引是字符串型的。这意味着“$hello["000"]”和“$hello[0]”也是不同的。

开发程序的时候应该仔细地考虑上面的问题,例如,我们不应该在一个地方测试某个变量是否为“0”,而在另外的地方使用empty()来验证。

[容易出错的函数]
我们在分析PHP程序中的漏洞时,如果能够拿到源代码的话,那么一份容易出错的函数列表则是我们非常需要的。如果我们能够远程改变这些函数的参数的话,那么我们就很可能发现其中的漏洞。下面是一份比较详细的容易出错的函数列表:

<PHP代码执行>
require():读取指定文件的内容并且作为PHP代码解释
include():同上
eval():把给定的字符串作为PHP代码执行
preg_replace():当与“/e”开关一起使用时,替换字符串将被解释为PHP代码

<命令执行>
exec():执行指定的命令,返回执行结果的最后一行
passthru():执行指定命令,返回所有结果到客户浏览器
``:执行指定命令,返回所有结果到一个数组
system():同passthru(),但是不处理二进制数据
popen():执行指定的命令,把输入或输出连接到PHP文件描述符

<文件泄露>
fopen():打开文件,并对应一个PHP文件描述符
readfile():读取文件的内容,然后输出到客户浏览器
file():把整个文件内容读到一个数组中

译者注:其实这份列表还不是很全,比如“mail()”等命令也可能执行命令,所以需要自己补充一下。
[如何增强PHP的安全性]
我在上面介绍的所有攻击对于缺省安装的PHP 4都可以很好的实现,但是我已经重复了很多次,PHP的配置非常灵活,通过配置一些PHP选项,我们完全可能抵抗其中的一些攻击。下面我按照实现的难度对一些配置进行了分类:

*低难度
**中低难度
***中高难度
****高难度

上面的分类只是个人的看法,但是我可以保证,如果你使用了PHP提供的所有选项的话,那么你的PHP将是很安全的,即使是第三方的代码也是如此,因为其中很多功能已经不能使用。

**** 设置“register_globals”为“off”
这个选项会禁止PHP为用户输入创建全局变量,也就是说,如果用户提交表单变量“hello”,PHP不会创建“$ hello”,而只会创建“HTTP_GET/POST_VARS['hello']”。这是PHP中一个极其重要的选项,关闭这个选项,会给编程带来很大的不便。

*** 设置“safe_mode”为“on”
打开这个选项,会增加如下限制:
1.    限制哪个命令可以被执行
2.    限制哪个函数可以被使用
3.    基于脚本所有权和目标文件所有权的文件访问限制
4.    禁止文件上载功能
这对于ISP来说是一个伟大的选项,同时它也能极大地改进PHP的安全性。

** 设置“open_basedir”
这个选项可以禁止指定目录之外的文件操作,有效地消除了本地文件或者是远程文件被include()的攻击,但是仍需要注意文件上载和session文件的攻击。

** 设置“display_errors”为“off”,设置“log_errors”为“on”
这个选项禁止把错误信息显示在网页中,而是记录到日志文件中,这可以有效的抵制攻击者对目标脚本中函数的探测。

* 设置“allow_url_fopen”为“off”
这个选项可以禁止远程文件功能,极力推荐!

好了,文章到此为止了,如果你想了解一些其它的相关信息,请参考原文http://www.securereality.com.au/studyinscarlet.txt。

<全文完>

PHP 相关文章推荐
PHP4和PHP5共存于一系统
Nov 17 PHP
PHP连接access数据库
Mar 27 PHP
PHP采集相关教程之一 CURL函数库
Feb 15 PHP
PHP Zip压缩 在线对文件进行压缩的函数
May 26 PHP
win7+apache+php+mysql环境配置操作详解
Jun 10 PHP
php删除数组元素示例分享
Feb 17 PHP
php过滤html中的其他网站链接的方法(域名白名单功能)
Apr 24 PHP
浅谈php冒泡排序
Dec 30 PHP
php对象在内存中的存在形式分析
Feb 03 PHP
PHP实现登陆表单提交CSRF及验证码
Jan 24 PHP
Yii2处理密码加密及验证的方法
May 12 PHP
PHP Pipeline 实现中间件的示例代码
Apr 26 PHP
模拟OICQ的实现思路和核心程序(三)
Oct 09 #PHP
模拟OICQ的实现思路和核心程序(一)
Oct 09 #PHP
PHP自动更新新闻DIY
Oct 09 #PHP
模拟OICQ的实现思路和核心程序(二)
Oct 09 #PHP
层叠菜单的动态生成
Oct 09 #PHP
多数据表共用一个页的新闻发布
Oct 09 #PHP
PHP与MySQL交互使用详解
Oct 09 #PHP
You might like
php 文件上传系统手记
2009/10/26 PHP
简单PHP上传图片、删除图片实现代码
2010/05/12 PHP
phpStudy访问速度慢和启动失败的解决办法
2015/11/19 PHP
yii2实现Ueditor百度编辑器的示例代码
2018/11/02 PHP
jQuery提交多个表单的小例子
2013/06/30 Javascript
AngualrJS中每次$http请求时的一个遮罩层Directive
2016/01/26 Javascript
BootStrap下jQuery自动完成的样式调整
2016/05/30 Javascript
Angular.js 实现数字转换汉字实例代码
2016/07/14 Javascript
简单三步实现报表页面集成天气
2016/12/15 Javascript
Angular动态添加、删除输入框并计算值实例代码
2017/03/29 Javascript
微信小程序实现给嵌套template模板传递数据的方式总结
2017/12/18 Javascript
webpack打包并将文件加载到指定的位置方法
2018/02/22 Javascript
详解React项目的服务端渲染改造(koa2+webpack3.11)
2018/03/19 Javascript
详解vue-cli官方脚手架配置
2018/07/20 Javascript
详解js中let与var声明变量的区别
2020/04/05 Javascript
详解新手使用vue-router传参时注意事项
2019/06/06 Javascript
Vue的路由及路由钩子函数的实现
2019/07/02 Javascript
JS实现拖拽元素时与另一元素碰撞检测
2020/08/27 Javascript
Python类方法__init__和__del__构造、析构过程分析
2015/03/06 Python
使用py2exe在Windows下将Python程序转为exe文件
2016/03/04 Python
Python使用Flask-SQLAlchemy连接数据库操作示例
2018/08/31 Python
uwsgi+nginx部署Django项目操作示例
2018/12/04 Python
Pytorch 实现自定义参数层的例子
2019/08/17 Python
Python的控制结构之For、While、If循环问题
2020/06/30 Python
Python selenium模块实现定位过程解析
2020/07/09 Python
快速解释如何使用pandas的inplace参数的使用
2020/07/23 Python
python如何编写类似nmap的扫描工具
2020/11/06 Python
利用CSS的Sass预处理器(框架)来制作居中效果
2016/03/10 HTML / CSS
内部类的定义、种类以及优点
2013/10/16 面试题
网络程序员自荐信
2014/01/25 职场文书
学校师德承诺书
2014/05/23 职场文书
2014年有孩子的离婚协议书范本
2014/10/08 职场文书
幼儿园迎新生欢迎词
2015/09/30 职场文书
Nginx 502 Bad Gateway错误原因及解决方案
2021/03/31 Servers
python中的class_static的@classmethod的巧妙用法
2021/06/22 Python
GO语言字符串处理函数之处理Strings包
2022/04/14 Golang