标题: ThinkPHP框架通杀所有版本的一个SQL注入漏洞 [打印本页] 作者: admin 时间: 2013-7-27 18:30 标题: ThinkPHP框架通杀所有版本的一个SQL注入漏洞 下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。4 b6 T3 R* b( n' Z, G6 y
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件 . _2 V8 }4 }' s4 ]5 G v根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html) ; H5 ^% a3 x2 s! U, S使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:1 }! C7 `9 o, |
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select();4 m) J3 r: w* s/ E8 b0 z& ^
: C7 B$ f9 j- t7 { c3 c a 或者 7 Q5 P& R0 @2 ?7 p- y/ i. [1 U$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select(); & \7 \7 j- `3 L5 q/ l ; _! e% @6 o; M/ O& e0 F 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入):; w1 d, g+ e/ f! D8 j4 B
$model->query('select * from user where id=%d and status=%s',$id,$status);. a% g% }8 e7 V n% A/ Y
7 ~1 N8 ]4 Z. B0 Z' O或者 4 w! U" K' T9 l1 V9 x' I$model->query('select * from user where id=%d and status=%s',array($id,$status)); ; j$ r" q: p- ^% L; `4 l$ D! {) l8 o) S# [ v c
原因:8 t( r- h0 Y4 p" `( z' o
ThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤. # V- Z4 s0 W) R5 S原函数:+ z% o9 D" j+ u7 d6 u9 w/ L% e. H6 L: \
protected function parseSql($sql,$parse) {# Z7 y5 | T, I6 l
// 分析表达式 5 E/ R* k" O$ |, M, g" _ if(true === $parse) { 3 }) J2 H# j" ^ $options = $this->_parseOptions();/ x1 w/ y: T$ [ C7 L3 r
$sql = $this->db->parseSql($sql,$options);' `: M' t7 x. a( i3 Y" o' I+ W
}elseif(is_array($parse)){ // SQL预处理* d9 C5 u9 B' @% ~, o9 m: b2 t
$sql = vsprintf($sql,$parse); 2 w7 E9 A$ K! U S/ { }else{ ( N/ W, X& o9 K% B0 {9 C# V: n8 d3 d1 o $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));& v" l. |6 c5 g
} ( B4 ^2 ~8 Z; y, l6 ` $this->db->setModel($this->name);1 H7 W2 h8 B8 ?7 }
return $sql; q' _3 q$ m7 u& z# a } 5 R* w: w( B$ g/ V! Z8 h5 _! s6 w9 T- [; p1 k$ o) |" j2 N# _
验证漏洞(举例): 3 H8 ]( R6 k1 U$ R请求地址: " {& ~" p9 e6 F' ?' W1 ~$ \0 L/ @http://localhost/Main?id=boo” or 1=”1 9 H0 N7 f. S5 T( _/ @; j' q0 E( H或 & ~/ M( }0 }2 Ohttp://localhost/Main?id=boo%22%20or%201=%2217 h' C3 k6 q' w$ d
action代码:/ ^- R5 ~! a' d) G
$model=M('Peipeidui');* b' l; x, W& i4 G
$m=$model->query('select * from peipeidui where name="%s"',$_GET['id']);5 D3 a4 a" N% g- T; J. d) b) F
dump($m);exit; 3 j) Z+ d- i5 C或者 % W, Y. F5 T; u$ L. o- [0 h* t$model=M('Peipeidui'); l' Y: E6 ^. N# z2 l$ P2 Y $m=$model->query('select * from peipeidui where name="%s"',array($_GET['id']));; [9 ? Y6 L1 l, j4 \4 j3 e
dump($m);exit; ! N. U# c' U. h7 ~) m0 ~' O结果: ) p" c8 F# @) ~+ K表peipeidui所有数据被列出,SQL注入语句起效.7 U5 P2 M0 g3 w O
解决办法: Z5 Y% a, |+ Y5 H/ n
将parseSql函数修改为:& Y" D" |0 n2 M `8 G
protected function parseSql($sql,$parse) { # }4 P4 N$ A% d // 分析表达式 4 l' \; P6 ?7 z( V- x$ f% m2 z if(true === $parse) {5 g' V# F. w" J/ U
$options = $this->_parseOptions();: X# r$ \' O2 X# w; D
$sql = $this->db->parseSql($sql,$options); 0 n3 Q) |! @5 q' a* B }elseif(is_array($parse)){ // SQL预处理 # J& Q$ d* Y, t) a4 Y $parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码 1 {$ z0 m: h0 Z# L5 V9 G- r $sql = vsprintf($sql,$parse); & L+ ]& j" M0 C! x9 s2 M }else{ # y) y+ ]2 g1 w5 N+ p $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); {& A4 J: t# h9 z) T }, Q u- _& F, P/ a% r0 @( y |2 b, O) h
$this->db->setModel($this->name); & S, ]+ `8 {# L! H" n return $sql;7 R4 U. d( h+ ?/ b3 Y' J
}9 z& v8 O7 I8 u4 P3 n
. v9 O4 o& _: L5 a
总结:; m+ t' T" c$ i. P; l0 |9 w( f
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查4 ?: [) X: ~ x% U, _/ X
不建议直接用$_GET,$_POST' e- A- m7 W9 G, U! _6 Q
[/td][/tr] e% l, D: @5 l U A& J# Z
[/table]+1 5 x) x0 G) P9 p( }$ y7 T; D / S, M/ E& m @2 G# y5 j 3 T5 | ]+ A0 ? S