2017 0CTF simplesqlin

没打0ctf, 但是在看大佬们的writeup的时候发现了这道题。

当时就觉得这个绕过莫名其妙, 不知道是怎么写的过滤。
看了几个博客, 好像都不太清楚绕过的原理,就这样测了下就绕过去了。

不过,当看到这题的flag之后,就大概知道为什么在payload之间插入%00这种可以绕过了。flag是flag{W4f_bY_paSS_FOR_CI} 也就是waf bypass for ci, 也就是用了ci框架清除一些字符的特性来bypass了waf.

在system/core/Input.php的构造方法中

1
2
3
4
   public function __construct()
{
省略
$this->_sanitize_globals(); //净化全局变量,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
   	protected function _sanitize_globals()
{
// Is $_GET data allowed? If not we'll set the $_GET to an empty array
if ($this->_allow_get_array === FALSE)
{
$_GET = array();
}
elseif (is_array($_GET))
{
foreach ($_GET as $key => $val)
{
$_GET[$this->_clean_input_keys($key)] = $this->_clean_input_data($val);
}
}
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
protected function _clean_input_data($str)
{
if (is_array($str))
{
$new_array = array();
foreach (array_keys($str) as $key)
{
$new_array[$this->_clean_input_keys($key)] = $this->_clean_input_data($str[$key]);
}
return $new_array;
}

/* We strip slashes if magic quotes is on to keep things consistent

NOTE: In PHP 5.4 get_magic_quotes_gpc() will always return 0 and
it will probably not exist in future versions at all.
*/
if ( ! is_php('5.4') && get_magic_quotes_gpc())
{
$str = stripslashes($str);
}

// Clean UTF-8 if supported
if (UTF8_ENABLED === TRUE)
{
$str = $this->uni->clean_string($str);
}

// Remove control characters
$str = remove_invisible_characters($str, FALSE);

这里看注释就能大概看出来清掉了哪些啦。
Clean UTF-8 if supported、Remove control characters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function remove_invisible_characters($str, $url_encoded = TRUE)
{
$non_displayables = array();

// every control character except newline (dec 10),
// carriage return (dec 13) and horizontal tab (dec 09)
if ($url_encoded)
{
$non_displayables[] = '/%0[0-8bcef]/i'; // url encoded 00-08, 11, 12, 14, 15
$non_displayables[] = '/%1[0-9a-f]/i'; // url encoded 16-31
$non_displayables[] = '/%7f/i'; // url encoded 127
}

$non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127

do
{
$str = preg_replace($non_displayables, '', $str, -1, $count);
}
while ($count);

return $str;
}

这里应该是在清空这些字符之前就检测了字符,
所以呢 这里不止%00能绕过, %12, %80-%99之类的不少字符都能绕过。

后面一开始也在想, 这题都没用ci框架那种常见的url route, 也没看到啥明显的特征提示是ci框架,大家怎么能想到是利用ci框架的这个特性来绕过呢,不过后面发现在404页面中使用的是熟悉的ci框架的404页面, 那么也就很简单了。