手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜Qcloud , 注册 | 登陆

MySQL和SQL字段截短漏洞

首页 > DataBase >

这篇文章很有意思,以前注意过,但没仔细考虑过用来注入,或许就象王猛说的:

    了解很长一段时间的web安全了,个人觉得世上最聪明的程序员其实是黑客,一次想N步,逻辑超强,技术全面,从操作系统漏洞、到语言本身漏洞、数据库本身漏洞、再到开发者代码,无孔不入。

文章来自寂寞hacker,http://hi.baidu.com/isbx/blog/item/08ef48547ef1ad58574e00bf.html:
当前的Web开发者中肯定有不少人没有注意到作者所提到的这两个问题的。

第一个问题是这样的,MySQL默认有一个配置参数 max_packet_size,这个参数是用于限制MySQL客户端和MySQL服务器端数据通信的数据包大小,MySQL的默认配置是1MB。如果客 户端发送的数据超过了1MB,则MySQL服务器端会忽略掉这个请求数据。作者接下来举了两个利用这个缺陷的例子,第一个是利用超长数据来使MySQL的 日志记录程序失效,第二个是在PHP+MySQL的环境下,PHP的Session清理程序会由于一次发送的清理session数据的请求数据包超过 max_packet_size的限制,而导致清理session失败。

而实际上,由于很多PHP+MySQL的程序都会运行用户上传附件之类,而一般的PHP+MySQL的上传附件限制都是大于1MB的,所以PHP的 程序开发人员一般是会去修改max_packet_size的值为大于1MB。这就给我们的漏洞利用带来了一定的麻烦,毕竟在当前的网络状况下,构造 1MB多的数据去上传还是可以忍受的。但是太大的数据量就比较考验我们的耐心了,呵呵。

第二个问题就比较严重了,MySQL对于超过字段长度的数据插入操作会进行默认的字符串截短。例如一个字段定义的长度为10,如果插入的字符串长度 超过10,MySQL会将长度超过10的部分字符串自动舍去后插入到数据表中。默认配置条件下,MySQL会产生一个警告信息,但是这个警告信息不会被 Web应用程序捕获到。所以,从表面上来看,超长数据也是可以“成功”插入数据表的。作者在下面举的这个例子就很有代表性了,首先是一个场景假设:

  • The application is a forum where new users can register
  • The administrator’s name is known e.g. ‘admin’
  • MySQL is used in the default mode
  • There is no application restriction on the length of new user names
  • The database column username is limited to 16 characters

用户如果尝试注册一个用户名为admin的用户,会由于Web应用程序中的isAlreadyRegistered函数的校验而注册失败。

SQL代码
  1. SELECT * FROM user WHERE username='admin'  

但如果用户使用用户名’admin           x’来注册(注意admin和x之间有11个空格),则注册流程会是这样的:

isAlreadyRegistered函数会使用上面的SQL语句来检查user表中是否存在相同用户名的用户,查询结果肯定是不存在的。那么用户注册成功!

实际上,真正插入到user表中的用户名是’admin’!也就是说,MySQL不仅会截短超过长度限制部分的字符串,也会对字符串头尾的空白字符进行截短!所以,在user表中,现在存在了两个admin用户!

接下来,用户登陆,他使用的是用户名admin,密码是他刚才设置的’admin           x’的密码。假设Web应用程序的登陆认证和授权函数是这样的一段代码:

PHP代码
  1. $userdata = null;  
  2. if (isPasswordCorrect($username$password)) {  
  3.    $userdata = getUserDataByLogin($username);  
  4.    ...  
  5. }  

其中isPasswordCorrect函数使用的SQL语句为:

SQL代码
  1. SELECT username FROM users WHERE username = ? AND passhash = ?  

getUserDataByLogin函数使用的SQL语句为:

SQL代码
  1. SELECT * FROM users WHERE username = ?  

可以看得出,上面的语句使用了预编译的SQL语句,是无法实施SQL注入的。但是由于MySQL的默认字段截短策 略,isPasswordCorrect函数会成功执行并返回用户名admin,接下来的getUserDataByLogin也会正确执行,返回的结果 虽然是一个数组,但是Web应用程序一般是取返回数组中的第一个结果,也就是真正的管理员用户admin的所有数据!

怎么样,不用SQL注入,一样拿到管理员权限!

后记:经过测试,上面的漏洞利用过程在MySQL 4中是确实存在并且可以利用的。但是在MySQL 5中,本机测试失败。失败的关键就在于MySQL 5对于超过字段长度限制的字符串插入会报错,并停止字符串插入操作。

附:MySQL 4的测试过程

SQL代码
  1. mysql> select * from tb_sqltest where name='jason';  
  2. +----+-------+--------+------+------+------+------+  
  3. | id | name  | remark | time | col1 | col2 | col3 |  
  4. +----+-------+--------+------+------+------+------+  
  5. |  1 | jason | NULL    | NULL | NULL | NULL | NULL |  
  6. +----+-------+--------+------+------+------+------+  
  7. 1 row in set  
  8.   
  9. mysql> select * from tb_sqltest where name='jason        x';  
  10. Empty set  
  11.   
  12. mysql> insert into tb_sqltest (id,namevalues (2,'jason        x');  
  13. Query OK, 1 row affected  
  14.   
  15. mysql> select * from tb_sqltest where name='jason';  
  16. +----+-------+--------+------+------+------+------+  
  17. | id | name  | remark | time | col1 | col2 | col3 |  
  18. +----+-------+--------+------+------+------+------+  
  19. |  1 | jason | NULL    | NULL | NULL | NULL | NULL |  
  20. |  2 | jason | NULL    | NULL | NULL | NULL | NULL |  
  21. +----+-------+--------+------+------+------+------+  
  22. rows in set  

 

 

 

 

 




本站采用创作共享版权协议, 要求署名、非商业和保持一致. 本站欢迎任何非商业应用的转载, 但须注明出自"膘叔", 保留原始链接, 此外还必须标注原文标题和链接.

Tags: mysql

« 上一篇 | 下一篇 »

只显示10条记录相关文章

1条记录访客评论

- -不知道用唯一索引能不能避免这个问题?

Post by 爆波团队长 on 2010, April 25, 8:42 PM 引用此文发表评论 #1


发表评论

评论内容 (必填):