[翻译]php安全之谜(PHP Undergroud Security)
文章作者:Omnipresent译文作者:riusksk(泉哥)
信息来源:邪恶八进制信息安全团队([url]www.eviloctal.com[/url])
-[ 作者信息 ]-----------------------------------------------------------------------
标题: "PHP Undergroud Security"
作者: Omnipresent
邮箱: [email]omnipresent@email.it[/email] - [email]omni@playhack.net[/email]
主页: [url]http://omni.playhack.net[/url] - [url]http://www.playhack.net[/url]
日期: 2007-04-12
---------------------------------------------------------------------------------
-[ 译者信息 ]-----------------------------------------------------------------------
译者:riusksk(泉哥)
邮箱:riusksk@qq.com
主页: [url]http://riusksk.blogbus.com[/url]
日期:2008-11-15
---------------------------------------------------------------------------------
-[ 摘要 ]---------------------------------------------------------------------
0x00: 前言
0x01: 关注全局变量
[*] 修补
0x02: 文件包含
[*] 修补
0x03: 跨站脚本
0x04: SQL注入
\_ 0x04a: 绕过登陆验证
\_ 0x04b: 1 Query? No.. 2 one!(译注:不好翻译,还是保留原文吧!)
[*] 修补
0x05: 文件遍历
[*] 修补
0x05: 结论
---[ 0x00: 前言]
大家好!首先对我糟糕的英语表示抱歉,因为它不是我的母语.
在本教程中,我将会向大家介绍一些主要的php漏洞,以及如何发现、利用并修补它!
-----------------------------------------------------------------------------[/]
---[ 0x01: 关注全局变量]
在php中,你并不一定需要声明变量(这对程序员来说确实是件好事),当你必须使用它时它会“自动”创建的。你可能认为这是件不错的事,确实如此,但这只是偶而发生的事情。
众所周之,PHP经常要获取用户的输入值,并对其进行处理。假如我们在使用一个未声明过的变量时,就可能会引发web程序的安全问题。例如下面一段代码:
[...]
if ($is_admin == 1) {
//Yes, I'm the admin so call the Administration Pannel
[...]
} else {
//No, I'm not the admin
[...]
}
上面的变量$is_admin ,我们在使用前并未声明过,那么我们是否可以绕过该变量(在bugged.php文件中)而访问未经授权的管理面板呢?答案是肯定,但我们该如何添加管理认证权限呢?其实很简单,比如:
http://remote_host/bugged.php?is_admin=1
---[ 修补 ]---
如何修补该漏洞呢?这很容易:在if语句前声明变量$is_admin 即可,代码如下:
$is_admin = 0;
[...]
if ($is_admin == 1) {
//Yes, I'm the admin so call the Administration Pannel(为真,则说明是管理员,因此被重定向管理界面)
[...]
} else {
//No, I'm not the admin(为假,则不是管理员)
[...]
}
-----------------------------------------------------------------------------[/]
---[ 0x02: 文件包含]
-----[本地文件包含]
PHP是种杰出的语言,强大而简单;但是如果你不想在你的代码中出现安全问题,那么你就必须注意一下你的代码了。
在一些情况下,使用动态包含文件(部分路径名存在某个变量中)确实是件好事。让我们看一下下面的代码:
<?php
include "/users/".$include_path.".php";
[...]
?>
变量$include_path 在使用前并未进行任何声明,因此攻击者可以在该变量中输入恶意数据,使其包含其它文件(比如/etc/passwd..)。
用户通过修改URL中的$include_path 变量值可以很容易浏览其它文件。例如:
http://remote_host/bugged.php?include_path=../../../../etc/passwd%00
包含后的结果如下:
<?php
include "/users/../../../../etc/passwd%00.php"
[...]
?>
因此攻击者可以窃取到存在服务器上的所有密码。
- [ 注意 ] -
%00是一个NULL字符,用于“删除”PHP文件扩展名。如果省略掉NULL,将只会显示PHP文件的内容,因为包含文件的扩展名是PHP(include "/users/".$include_path.".PHP")
-------------------------------------------------------------------------------
-----[ 远程文件包含]
先看一下下面的代码:
<?php
[...]
include($_GET['pag']);
[...]
?>
正如我们所看到的,变量$page 在使用前并未进行任何验证,因此恶意用户可以通过浏览器包含或者调用他的脚本,从而获得被害者电脑的访问权或者像上面说的一样——浏览文件。
例1(提权):
http://remote_host/inc.php?pag=[Evil Script - our shell located on our server]
例2(浏览文件):
http://remote_host/inc.php?pag=/etc/passwd
---[ 修补 ]---
如何解决这种问题呢?验证输入值就可以了。用得最多的一个验证方法就是创建一个可访问页面的列表,如下:
[...]
$pag = $_GET['pag'];
$pages = array('index.php', 'alfa.php', 'beta.php', 'gamma.php');
if(in_array($pag, $pages))
{
include($pag);
{
else
{
die("Hacking Attempt!");
}
[...]
-----------------------------------------------------------------------------[/]
---[ 0x03: 跨站脚本]
你是否想知道一些关于XSS的资料呢?关于这方面的内容,我的朋友已经写了很多了,我想我没必要再做重复的工作了,具体可以看下面的链接:
[+] "Cross-Site Scripting for Fun and Profit"
[url]http://www.playhack.net/view.php?type=1&id=18[/url]
[+] "Applying XSS to Phishing Attacks"
[url]http://www.playhack.net/view.php?type=1&id=20[/url]
-----------------------------------------------------------------------------[/]
---[ 0x03: SQL 注入]
SQL注入,如名字所述:在一个存在漏洞的WEB程序中,你可以在请求语句中注入SQL语句。
-----------------------------------------------------------------------------[/]
------[ 0x04b 绕过登陆验证]
在举例之前,我们必须先知晓一些关于SQL的内容:
- (') 这是什么呢?对攻击者来说,这是一个SQL语法中的操作符,这在漏洞攻击中是非常重要的,它可以用于划分字符串…
- (#) 用于注释,'#'(没有分号),这在SQL语法中用于作注释用的。记住它,因为它非常实用和重要!
- (;) 这个符号在数据库中可以用于构造新的请求语句。呆会我们看一下用它来入侵的实际操作,先看一下下面的例子(绕过登陆验证--获取管理权限):
<?php
// login.php
$nick = $_POST['nick'];
$pass = $_POST['pass'];
$link = mysql_connect('localhost', 'root', 'root') or die('Error: '.
mysql_error());
mysql_select_db("sql_inj", $link);
$query = mysql_query("SELECT * FROM sql_inj WHERE nick ='".$nick."' AND pass ='" .$pass. "'",
$link);
if (mysql_num_rows($query) == 0) {
echo "<script type=\"text/javascript\">window.location.href='index.html';</script>";
exit;
}
$logged = 1;
[...]
//EoF
?>
虽然这段脚本代码非常简单,但是这在学习SQL注入时非常有用。正如我们所看到的,变量$nick和 $pass用于SQL请求时并未进行任何有效地验证,因此我们可以注入我们的SQL代码!看一下下面的请求语句:
"SELECT * FROM sql_inj WHERE nick ='".$nick."' AND pass ='" .$pass. "'"
What happends if we pass two variables tainted like these:
假如我们输入经恶意构造的这两个变量,那么将会发生什么事呢,例如:
$nick = 1' OR '1' = '1
$pass = 1' OR '1' = '1
The new query will be:
构成新的请求语句:
"SELECT * FROM sql_inj WHERE nick ='1 OR '1' = '1' AND pass ='1' OR '1' = '1'"
如果你已经知道了关于数据库中的表的知识,但还未弄清楚上面的语句,那么可以看看下面的解释,以帮助你理解它。
1 OR 1 = 1 ??
1或者1等于1?很明显的!那么谁是'sql_inj'表中的第一位用户呢?会是安装这一WEB程序的人吗?没错!就是管理员。
因此我们可以以管理员的身份登陆网站,这样我们就成为管理员了,酷吧!
我们也可以输入下列请求:
$nick = 1' OR '1' = '1' #
$pass = what_we_want_to_put
构成新一请求语句:
"SELECT * FROM sql_inj WHERE nick ='1 OR '1' = '1' # AND pass = what_we_want_to_put"
之前我们已经说过'#'是注释用的!现在我们重新构成新的请求语句:
"SELECT * FROM sql_inj WHERE nick ='1 OR '1' = '1'
现在我们又变成管理员了:D
------[ 0x04b: 1 Query? No.. 2 one! ]
通过SQL注入,我们可以通过修改请求语句,从而注入新的数据,更改用户资料,还可以做其它事……让我们看一下下面的源代码:
<?php
//email.php
[...]
$email = $_POST['email'];
[...]
$query = mysql_query("SELECT email, passwd, user_name FROM users WHERE email =
'".$email."'");
[...]
?>
在这里,变量$email 在使用前并未进行任何有效地验证,因此我们可以利用它了。比如通过输入像下面的变量值就可以很容易地更新数据库信息了:
$email = x'; UPDATE users SET email = 'omnipresent@email.it'
WHERE email = 'admin@site.com ';
构造新的请求语句:
SELECT email, passwd, user_name FROM users
WHERE email = ' x'; UPDATE users SET email = 'omnipresent@email.it'
WHERE email = 'admin@site.com ';
这里攻击者可以修改 'users' 表,特别是管理员的邮箱,利用他的邮箱,我可以通过“忘记了密码?”这一链接,利用邮箱(这里是[email]omnipresent@email.it[/email])接收一封像下列内容的邮件,从而达到目的:
From: [email]host@site.com[/email]
To: [email]omnipresent@email.it[/email]
Subject: Login Password
Ehy.. take it ;)
Username: Admin
Password: 12345
Regards,
Admin
---[ 修补 ]---
首先可以通过修改php.ini文件来修补脚本漏洞:
1. 在所有的' (单引号) , “ (双引号) , \ (反斜线)以及NULL前自动加上转义符——反斜线“\”
-COOKIE
-POST
-GET
2. 在字符串前加上斜线‘/’
3. 将指定的字符转换为HTML实体
4.转义在mysql-query中使用的字符串
5. 可以到 [url]www.php.net[/url] 查看更多的函数
(译注: [url]www.php.net[/url] 是一个不错的PHP在线查询站点,我经常用它来查询PHP函数及其它相关资料。)
6. 验证用户提取的数据,例如:
$user_id = (int)$_GET['user_id'];
$user_id is always an integer and we can cast the input for securing
our web applications.
变量$user_id 总为整数,这样就可以确保在WEB程序中输入数据的安全了。
-----------------------------------------------------------------------------[/]
---[ 0x05: 文件遍历]
遍历文件是一个十分危重的漏洞,下面简单讲解一下该漏洞。
无论在什么时候,当我们需要使用文件时都需要检查一下脚本中的文件名及其路径。
在大多情况下,文件名都是作为函数fopen()的参数来传输的,比如:
<?php
[...]
$fp = fopen("/path/{$_GET['filename']}.txt", 'r');
[...]
?>
由于在这段脚本代码中'filename' 可被被远程用户修改破坏,这就造成了文件遍历漏洞。
在这种情况下,攻击者可以通过使用多个"../"来移动目录查看文件。
例如:
http://remote_host/path/bug.php?filename=../../../../path_of_another_file/file%00
NULL Byte (%00)在许多攻击中多用于截断字符串,以突破文件扩展名的限制。
---[ 修补 ]---
修补这一漏洞最好的方法就是使用basename()函数,例如:
<?php
$clean = array();
if (basename($_GET['filename']) == $_GET['filename'])
{
$clean['filename'] = $_GET['filename'];
}
else
{
[...]
}
$fp = fopen("/path/{$clean['filename']}.txt", 'r');
?>
-----------------------------------------------------------------------------[/]
---[ 0x06: 结论 ]
这是"PHP Undergroud Security"的结尾了,希望本文对你打造php安全代码有所帮助!
有任何问题可发送邮件至 [email]omnipresent@email.it[/email] 或者 [email]omni@playhack.net[/email] 。
-----------------------------------------------------------------------------[/]
\=======================[EOF]============== ====== / 不是很详细,但是都把现在php中的安全问题提及了…… *** 作者被禁止或删除 内容自动屏蔽 *** 谢谢楼主的翻译 写的蛮不错的 有点杂乱无章,实话. *** 作者被禁止或删除 内容自动屏蔽 *** 好东西。谢了。还是英语好点好。 虽说,程序英语水平不一定要到达什么什么水平以上,
不过,英语好点,对程序有非常非常大的帮助 非常不错 我非常喜欢 :loveliness: 有了一小点收获哦
哎:victory:
页:
[1]
