压在透明的玻璃上c-国产精品国产一级A片精品免费-国产精品视频网-成人黄网站18秘 免费看|www.tcsft.com

從WordPress SQLi談PHP格式化字符串問題

作者:知道創(chuàng)宇404實(shí)驗(yàn)室

0x00 背景

近日,WordPress爆出了一個(gè)SQLi漏洞,漏洞發(fā)生在WP的后臺(tái)上傳圖片的位置,通過修改圖片在數(shù)據(jù)庫中的參數(shù),以及利用php的sprintf函數(shù)的特性,在刪除圖片時(shí),導(dǎo)致'單引號(hào)的逃逸。漏洞利用較為困難,但思路非常值得學(xué)習(xí)。

0x01 漏洞分析

漏洞發(fā)生在wp-admin/upload.php的157行,進(jìn)入刪除功能,

之后進(jìn)入函數(shù)wp_delete_attachment( $post_id_del )$post_id_del可控,而且沒有做(int)格式轉(zhuǎn)化處理。

wp_delete_attachment位于wp-includes\post.php的 4863 行。其中

圖片的post_id被帶入查詢,$wpdb->prepare中使用了sprintf,會(huì)做自動(dòng)的類型轉(zhuǎn)化,可以輸入22 payload,會(huì)被轉(zhuǎn)化為22,因而可以繞過。

之后進(jìn)入4898行的delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );函數(shù)。

delete_metadata函數(shù)位于wp-includes\meta.php的307行,

在這里代碼拼接出了如下sql語句,meta_value為傳入的media參數(shù)

SELECT meta_id FROM wp_postmeta WHERE meta_key = '_thumbnail_id' AND meta_value = 'payload'

之后這條語句會(huì)進(jìn)入查詢,結(jié)果為真代碼才能繼續(xù),所以要修改_thumbnail_id對應(yīng)的meta_value的值為payload,保證有查詢結(jié)果。

因此,我們需要上傳一張圖片,并在寫文章中設(shè)置為特色圖片

在數(shù)據(jù)庫的wp_postmeta表中可以看到,_thumbnail_id即是特色圖片設(shè)定的值,對應(yīng)的meta_value即圖片的post_id

原文通過一個(gè) WP<4.7.5 版本的xmlrpc漏洞修改_thumbnail_id對應(yīng)meta_value的值,或通過插件importer修改。這里直接在數(shù)據(jù)庫里修改,修改為我們的payload。

之后在365行,此處便是漏洞的核心,問題在于代碼使用了兩次sprintf拼接語句,導(dǎo)致可控的payload進(jìn)入了第二次的sprintf。輸入payload為22 %1$%s hello

代碼會(huì)拼接出sql語句,帶入$wpdb->prepare

SELECT post_id FROM wp_postmeta WHERE meta_key = '%s'  AND meta_value = '22 %1$%s hello'

進(jìn)入$wpdb->prepare后,代碼會(huì)將所有%s轉(zhuǎn)化為'%s',即meta_value = '22 %1$'%s' hello'

因?yàn)?strong>sprintf的問題 (vsprintf與sprintf類似) ,'%s'的前一個(gè)'會(huì)被吃掉,%1$'%s被格式化為_thumbnail_id ,最后格式化字符串出來的語句會(huì)變成

單引號(hào)成功逃逸!

最后payload為

http://localhost/wp-admin/upload.php?action=delete&media[]=22%20%251%24%25s%20hello&_wpnonce=bbba5b9cd3

這個(gè)SQL注入不會(huì)報(bào)錯(cuò),只能使用延時(shí)注入,而且需要后臺(tái)的上傳權(quán)限,所以利用起來比較困難。

0x02 漏洞原理

上述WordPress的SQLi的核心問題在于在sprintf中,'%s'的前一個(gè)'被吃掉了,這里利用了sprintfpadding功能

單引號(hào)后的一個(gè)字符會(huì)作為padding填充字符串。

此外,sprintf函數(shù)可以使用下面這種寫法

%后的數(shù)字代表第幾個(gè)參數(shù),$后代表類型。

所以,payload%1$'%s'中的'%被視為使用%進(jìn)行 padding,導(dǎo)致了'的逃逸。

0x03 php格式化字符串

但在測試過程中,還發(fā)現(xiàn)其他問題。php的sprintfvsprintf函數(shù)對格式化的字符類型沒做檢查。

如下代碼是可以執(zhí)行的,顯然php格式化字符串中并不存在%y類型,但php不會(huì)報(bào)錯(cuò),也不會(huì)輸出%y,而是輸出為空

<?php
$query = "%y";
$args = 'b';
echo sprintf( $query, $args ) ;
?>

通過fuzz得知,在php的格式化字符串中,%后的一個(gè)字符(除了'%')會(huì)被當(dāng)作字符類型,而被吃掉,單引號(hào)',斜杠\也不例外。

如果能提前將%' and 1=1#拼接入sql語句,若存在SQLi過濾,單引號(hào)會(huì)被轉(zhuǎn)義成\'

select * from user where username = '%\' and 1=1#';

然后這句sql語句如果繼續(xù)進(jìn)入格式化字符串,\會(huì)被%吃掉,'成功逃逸

<?php
$sql = "select * from user where username = '%\' and 1=1#';";
$args = "admin";
echo sprintf( $sql, $args ) ;
//result: select * from user where username = '' and 1=1#'
?>

不過這樣容易遇到PHP Warning: sprintf(): Too few arguments的報(bào)錯(cuò)。

還可以使用%1$吃掉后面的斜杠,而不引起報(bào)錯(cuò)。

<?php
$sql = "select * from user where username = '%1$\' and 1=1#' and password='%s';";
$args = "admin";
echo sprintf( $sql, $args) ;
//result: select * from user where username = '' and 1=1#' and password='admin';
?>

通過翻閱php的源碼,在ext/standard/formatted_print.c的642行

可以發(fā)現(xiàn)php的sprintf是使用switch..case..實(shí)現(xiàn),對于未知的類型default,php未做任何處理,直接跳過,所以導(dǎo)致了這個(gè)問題。

在高級php代碼審核技術(shù)中的5.3.5中,提及過使用$order_sn=substr($_GET["order_sn"], 1)截?cái)喑缘?code>\或"。

之前也有過利用iconv轉(zhuǎn)化字符編碼,iconv('utf-8', 'gbk', $_GET['word'])因?yàn)閡tf-8和gbk的長度不同而吃掉\。

幾者的問題同樣出現(xiàn)在字符串的處理,可以導(dǎo)致'的轉(zhuǎn)義失敗或其他問題,可以想到其他字符串處理函數(shù)可能存在類似的問題,值得去繼續(xù)發(fā)掘。

0x04 利用條件

  1. 執(zhí)行語句使用sprintfvsrptinf進(jìn)行拼接
  2. 執(zhí)行語句進(jìn)行了兩次拼接,第一次拼接的參數(shù)內(nèi)容可控,類似如下代碼
<?php

$input = addslashes("%1$' and 1=1#");
$b = sprintf("AND b='%s'", $input);
...
$sql = sprintf("SELECT * FROM t WHERE a='%s' $b", 'admin');
echo $sql;
//result: SELECT * FROM t WHERE a='admin' AND b=' ' and 1=1#'

0x05 總結(jié)

此次漏洞的核心還是sprintf的問題,同一語句的兩次拼接,意味著可控的內(nèi)容被帶進(jìn)了格式化字符串,又因?yàn)?code>sprintf函數(shù)的處理問題,最終導(dǎo)致漏洞的發(fā)生。

此問題可能仍會(huì)出現(xiàn)在WordPress的插件,原文的評論中也有人提到曾在Joomla中發(fā)現(xiàn)過類似的問題。而其他使用sprintf進(jìn)行字符串拼接的cms,同樣可能因此導(dǎo)致SQL注入和代碼執(zhí)行等漏洞。

0x06 參考鏈接

https://medium.com/websec/wordpress-sqli-bbb2afcc8e94

https://medium.com/websec/wordpress-sqli-poc-f1827c20bf8e

http://php.net/manual/zh/function.sprintf.php

https://github.com/php/php-src/blob/c8aa6f3a9a3d2c114d0c5e0c9fdd0a465dbb54a5/ext/standard/formatted_print.c

https://www.seebug.org/vuldb/ssvid-96376

上一篇:Xshell 高級后門完整分析報(bào)告

下一篇:Http協(xié)議 heap buffer overflow漏洞分析及利用