标题: ThinkPHP框架通杀所有版本的一个SQL注入漏洞 [打印本页] 作者: admin 时间: 2013-7-27 18:30 标题: ThinkPHP框架通杀所有版本的一个SQL注入漏洞 下面是摘自thinkphp官方的一个公告,官方直接贴出这些东西是非常不负责的行为,跟上次apache公开的Struts2的代码执行一样的行为,会造成很多用户被黑。建议类似的厂商不要再做这种蠢事。2 N' ^8 o) T1 K8 L# @) Y5 J
ThinkPHP 3.1.3及之前的版本存在一个SQL注入漏洞,漏洞存在于ThinkPHP/Lib/Core/Model.class.php 文件 , h) V, i4 O" u; u$ t根据官方文档对”防止SQL注入”的方法解释(见http://doc.thinkphp.cn/manual/sql_injection.html)( n, A" n; z/ x: Y
使用查询条件预处理可以防止SQL注入,没错,当使用如下代码时可以起到效果:) [8 v \0 m! V9 }
$Model->where("id=%d and username='%s' and xx='%f'",array($id,$username,$xx))->select(); , {5 `* Q4 c+ L" E) ?4 B8 B( W$ V( {, _0 _0 N' e
或者/ e- n% E' }* z' K4 v$ O
$Model->where("id=%d and username='%s' and xx='%f'",$id,$username,$xx)->select();- r& `. u, u, h+ n$ E" h
" g; Q. ?1 a, {! h6 Y4 P9 Y 但是,当你使用如下代码时,却没有”防止SQL注入”效果(而官方文档却说可以防止SQL注入): " f5 \$ R. ]( _1 U5 [3 n$model->query('select * from user where id=%d and status=%s',$id,$status);. h" J/ [- N) e/ l8 ^+ y
0 R: v1 h" G) k7 S- H- b' S或者 . W$ z, x! r9 o3 u2 E& {& ^$model->query('select * from user where id=%d and status=%s',array($id,$status)); # J5 _$ I, \- C/ d1 v/ W+ x+ R! a# n3 Z1 z
原因: 2 K( ~4 R( u8 h( lThinkPHP/Lib/Core/Model.class.php 文件里的parseSql函数没有实现SQL过滤. 3 [9 B3 `' O9 v% i& E原函数:5 t+ g H' @1 Y9 i/ r3 G) Y
protected function parseSql($sql,$parse) {2 e$ z2 U/ l4 b8 t% f/ B, n/ y" X& @
// 分析表达式7 \' O% \; `% ?1 E# g c
if(true === $parse) {# E" w2 R$ G( E$ K I
$options = $this->_parseOptions(); % |: }' p/ Z8 O: O5 X $sql = $this->db->parseSql($sql,$options); & _2 Z; y( t1 C) q3 X }elseif(is_array($parse)){ // SQL预处理 6 @7 C( l) o$ M $sql = vsprintf($sql,$parse); 3 D1 A F p8 L v/ Z% N. U }else{5 c2 p$ ~$ I6 Z7 y7 C3 L
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));9 @& S, i6 |0 H# m8 D2 m
}5 d$ r# b3 R8 i
$this->db->setModel($this->name);# r" d) b+ E X3 d7 v: l% s
return $sql; 6 I# l5 V. q$ |3 E; {/ V a6 B2 s } - q' v- i9 R* r: \0 K6 m8 f% ]* k) h/ b
验证漏洞(举例): ' g: c! ~' C& k, e3 i" `- q |请求地址:9 e: i. R+ v3 j& U+ {$ B
http://localhost/Main?id=boo” or 1=”12 Q& ~6 r% P: b, y1 g( D/ b& z
或8 V5 A/ a D/ f" M
http://localhost/Main?id=boo%22%20or%201=%221- e" l$ l6 R% x& `( c* ~5 n
action代码:6 ~% } m+ w- }2 @6 B
$model=M('Peipeidui'); , w1 @+ g/ V+ K1 A $m=$model->query('select * from peipeidui where name="%s"',$_GET['id']); & ?( ` U+ l3 R( n! u4 G dump($m);exit;% v3 _3 N" ]; Q# C/ s4 d/ ^4 y5 {
或者 2 }- _/ m0 D" M5 `# @/ E0 k J% a$model=M('Peipeidui');/ b+ c( j/ g ]
$m=$model->query('select * from peipeidui where name="%s"',array($_GET['id'])); 3 f0 P/ n' B5 B! K/ L" u dump($m);exit; 9 p6 w$ k. e4 q* i, e2 [( r$ X9 E, I结果: + E C6 \* N" X* x' m表peipeidui所有数据被列出,SQL注入语句起效. " e$ s9 q6 k5 S' l解决办法:" d0 w) |+ f4 R$ A
将parseSql函数修改为: v% T1 V* @' ^: F B7 _% v$ E
protected function parseSql($sql,$parse) { . e7 G5 o W7 V! W4 X6 |1 q+ T // 分析表达式 ! p3 [1 S, J& n: k9 O if(true === $parse) {: n* J2 B! q& E1 [0 r$ A
$options = $this->_parseOptions(); / T* ^- }* L* x6 x( H t7 @. v- c $sql = $this->db->parseSql($sql,$options); & H* @. L) X! v }elseif(is_array($parse)){ // SQL预处理- t' [; h! }9 b! T9 l L. l! C. s4 |
$parse = array_map(array($this->db,'escapeString'),$parse);//此行为新增代码& { `/ A' f1 M, S
$sql = vsprintf($sql,$parse); ; ? A- P u4 W; B }else{ 0 {, y6 { a) N( @2 H+ K3 G% K% a $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); * K. I. k9 N6 d9 M } t9 J8 k- ^; u5 S/ O7 |! o
$this->db->setModel($this->name); ' P/ k+ M5 A B4 G; d6 q return $sql; 7 h0 N- R6 L a) S% ^/ ?' E }& b9 v7 { U* F/ B1 v& ?; @
6 I9 e$ o2 i: J总结:* i4 G; V+ S( W3 @
不要过分依赖TP的底层SQL过滤,程序员要做好安全检查 # N% z. z2 Y. l& y8 I5 E8 P不建议直接用$_GET,$_POST9 [" h- g" O* U( X
[/td][/tr] ' W- X5 S$ S; Y[/table]+1: w& x! B" r. B: M& Y3 w3 [
/ `: @4 l( k w: [- N7 y" M
7 C, y; _: M! G