XOOPS 2.5.6  Final
 All Classes Namespaces Files Functions Variables Pages
ProtectorMysqlDatabase.class.php
Go to the documentation of this file.
1 <?php
2 
3 if( file_exists( XOOPS_ROOT_PATH.'/class/database/drivers/'.XOOPS_DB_TYPE.'/database.php' ) ) {
4  require_once XOOPS_ROOT_PATH.'/class/database/drivers/'.XOOPS_DB_TYPE.'/database.php';
5 } else {
6  require_once XOOPS_ROOT_PATH.'/class/database/'.XOOPS_DB_TYPE.'database.php';
7 }
8 
9 require_once XOOPS_ROOT_PATH.'/class/database/database.php' ;
10 
12 {
13 
14 var $doubtful_requests = array() ;
15 var $doubtful_needles = array(
16  // 'order by' ,
17  'concat' ,
18  'information_schema' ,
19  'select' ,
20  'union' ,
21  '/*' ,
22  '--' ,
23  '#' ,
24 ) ;
25 
26 
28 {
30  $this->doubtful_requests = $protector->getDblayertrapDoubtfuls() ;
31  $this->doubtful_needles = array_merge( $this->doubtful_needles , $this->doubtful_requests ) ;
32 }
33 
34 
35 function injectionFound( $sql )
36 {
38 
39  $protector->last_error_type = 'SQL Injection' ;
40  $protector->message .= $sql ;
41  $protector->output_log( $protector->last_error_type ) ;
42  die( 'SQL Injection found' ) ;
43 }
44 
45 
47 {
48  $sql = trim( $sql ) ;
49  $sql_len = strlen( $sql ) ;
50  $char = '' ;
51  $string_start = '' ;
52  $in_string = false;
53  $sql_wo_string = '' ;
54  $strings = array() ;
55  $current_string = '' ;
56 
57  for( $i = 0 ; $i < $sql_len ; $i ++ ) {
58  $char = $sql[$i] ;
59  if( $in_string ) {
60  while( 1 ) {
61  $new_i = strpos( $sql , $string_start , $i ) ;
62  $current_string .= substr( $sql , $i , $new_i - $i + 1 ) ;
63  $i = $new_i ;
64  if( $i === false ) {
65  break 2 ;
66  } else if( /* $string_start == '`' || */ $sql[$i-1] != '\\' ) {
67  $string_start = '' ;
68  $in_string = false ;
69  $strings[] = $current_string ;
70  break ;
71  } else {
72  $j = 2 ;
73  $escaped_backslash = false ;
74  while( $i - $j > 0 && $sql[$i-$j] == '\\' ) {
75  $escaped_backslash = ! $escaped_backslash ;
76  $j++;
77  }
78  if ($escaped_backslash) {
79  $string_start = '' ;
80  $in_string = false ;
81  $strings[] = $current_string ;
82  break ;
83  } else {
84  $i++;
85  }
86  }
87  }
88  } else if( $char == '"' || $char == "'" ) { // dare to ignore ``
89  $in_string = true ;
90  $string_start = $char ;
91  $current_string = $char ;
92  } else {
93  $sql_wo_string .= $char ;
94  }
95  // dare to ignore comment
96  // because unescaped ' or " have been already checked in stage1
97  }
98 
99  return array( $sql_wo_string , $strings ) ;
100 }
101 
102 
103 
104 function checkSql( $sql )
105 {
106  list( $sql_wo_strings , $strings ) = $this->separateStringsInSQL( $sql ) ;
107 
108  // stage1: addslashes() processed or not
109  foreach( $this->doubtful_requests as $request ) {
110  if( addslashes( $request ) != $request ) {
111  if( stristr( $sql , trim( $request ) ) ) {
112  // check the request stayed inside of strings as whole
113  $ok_flag = false ;
114  foreach( $strings as $string ) {
115  if( strstr( $string , $request ) ) {
116  $ok_flag = true ;
117  break ;
118  }
119  }
120  if( ! $ok_flag ) {
121  $this->injectionFound( $sql ) ;
122  }
123  }
124  }
125  }
126 
127  // stage2: doubtful requests exists and outside of quotations ('or")
128  // $_GET['d'] = '1 UNION SELECT ...'
129  // NG: select a from b where c=$d
130  // OK: select a from b where c='$d_escaped'
131  // $_GET['d'] = '(select ... FROM)'
132  // NG: select a from b where c=(select ... from)
133  foreach( $this->doubtful_requests as $request ) {
134  if( strstr( $sql_wo_strings , trim( $request ) ) ) {
135  $this->injectionFound( $sql ) ;
136  }
137  }
138 
139  // stage3: comment exists or not without quoted strings (too sensitive?)
140  if( preg_match( '/(\/\*|\-\-|\#)/' , $sql_wo_strings , $regs ) ) {
141  foreach( $this->doubtful_requests as $request ) {
142  if( strstr( $request , $regs[1] ) ) {
143  $this->injectionFound( $sql ) ;
144  }
145  }
146  }
147 }
148 
149 
150 function &query( $sql , $limit = 0 , $start = 0 )
151 {
152  $sql4check = substr( $sql , 7 ) ;
153  foreach( $this->doubtful_needles as $needle ) {
154  if( stristr( $sql4check , $needle ) ) {
155  $this->checkSql( $sql ) ;
156  break ;
157  }
158  }
159 
160  if( ! defined( 'XOOPS_DB_PROXY' ) ) {
161  $ret = parent::queryF( $sql , $limit , $start ) ;
162  } else {
163  $ret = parent::query( $sql , $limit , $start ) ;
164  }
165  return $ret ;
166 }
167 
168 }
169 
170 ?>