ThinkPHP一处过滤不当造成SQL注入漏洞
内核中某个模块开发的太粗糙啦。
问题出现在session,Thinkphp支持更换session handle。
handle中包括Db和Memcache,如下配置即可使用数据库作为session的存储器:
设置了选项后,在数据库里插入这个表(前缀think_可以自己定义):
1 2 3 4 5 6 7 8 9
| /** * 数据库方式Session驱动 * CREATE TABLE think_session ( * session_id varchar(255) NOT NULL, * session_expire int(11) NOT NULL, * session_data blob, * UNIQUE KEY `session_id` (`session_id`) * ); */
|
这都是官方给出的(包含在文档和代码注释中)一些配置方法,不多说了。
配置好了以后我写了个小example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php namespace Home\Controller; use Think\Controller; class AdminController extends Controller { function __construct(){ Controller::__construct(); session(array('name'=>'session_id','expire'=>3600)); }
public function index(){ $admin = session("admin"); if(!empty($admin)){ $this->show("欢迎登录,{$admin}",'utf-8'); }else{ $this->show('你没有登录,请登录','utf-8'); } }
public function login(){ session("admin", I('get.username')); $this->show('登录成功','utf-8'); } }
|
很普通一个过程,在login方法中登录,记录用户输入的用户名I('get.username')
作为$_SESSION['admin']
,在index方法中判断session中是否存在admin,不存在则要求其登录。
看到/ThinkPHP/Think/Session/Driver/Db.class.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public function write($sessID,$sessData) { $hander = is_array($this->hander)?$this->hander[0]:$this->hander; $expire = time() + $this->lifeTime; mysql_query("REPLACE INTO ".$this->sessionTable." ( session_id, session_expire, session_data) VALUES( '$sessID', '$expire', '$sessData')",$hander); if(mysql_affected_rows($hander)) return true; return false; }
|
实际上thinkphp将Db类中的open/close/read/write/destroy/gc用session_set_save_handler注册成为了session的handle。
write是设置session时的回调函数,其中$sessData
就是当前session经过serialize的值。我们看到这里直接将$sessData
拼接入SQL语句了,并没有转义。
所以造成了一个SQL注入。只要设置时session的值用户能够控制,比如用户名、昵称什么的,就能够产生SQL注入。
上述example脚本,访问http://xxxxx/thinkphp/index.php/home/admin/login?username=aaaaa%27aaaaaa
查看执行的SQL语句:
单引号已经带入了。
进行延时注入:
最后说一下,既然框架给开发者提供了自定义driver,那么这就作为框架的一部分进行维护,同样是不能草率的。不要因为不是默认使用的功能,就不去重视。
另外,内核部分的代码还使用SQL拼接这种方式去执行SQL语句,感觉不太合适。
且不论是否会产生sql注入,这里只要session的值中含有单引号,这个session就直接设置不了了,直接影响框架功能。所以需要在插入之前进行转义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
public function write($sessID,$sessData) { $hander = is_array($this->hander)?$this->hander[0]:$this->hander; $expire = time() + $this->lifeTime; $sessData = addslashes($sessData); mysql_query("REPLACE INTO ".$this->sessionTable." ( session_id, session_expire, session_data) VALUES( '$sessID', '$expire', '$sessData')",$hander); if(mysql_affected_rows($hander)) return true; return false; }
|