作為我們Sucuri防火墻(WAF)漏洞研究項(xiàng)目的一部分,為了查找存在的安全問題,我們已經(jīng)審計(jì)了多個(gè)開源項(xiàng)目。當(dāng)審計(jì)WordPress的“NextGEN”相冊(cè)插件時(shí),我們發(fā)現(xiàn)了一個(gè)嚴(yán)重的SQL注入漏洞。該漏洞允許一個(gè)未經(jīng)授權(quán)的用戶從受害人網(wǎng)站的數(shù)據(jù)庫(kù)中偷取數(shù)據(jù),包括用戶的敏感信息。目前,有超過100萬個(gè)WordPress網(wǎng)站安裝了這個(gè)易被攻擊的插件。
你處在危險(xiǎn)中嗎?
攻擊者利用該漏洞需要至少兩個(gè)條件:
在你的網(wǎng)站中是否使用了“NextGEN Basic TagCloud Gallery”?
你是否允許你網(wǎng)站的用戶提交要審閱的文章(投稿人)?
如果你的網(wǎng)站符合這兩種情況之一,那你已經(jīng)處在危險(xiǎn)之中了。
漏洞原因是NextGEN相冊(cè)允許用戶在WordPress執(zhí)行一條SQL查詢時(shí)輸入未經(jīng)過濾的數(shù)據(jù),本質(zhì)上就是將用戶輸入直接添加到了一條SQL查詢中。使用該攻擊方法,一個(gè)攻擊者可以偷取到密碼的HASH、和WordPress其它配置的秘密信息。
技術(shù)細(xì)節(jié)
永遠(yuǎn)不要相信輸入數(shù)據(jù)---這是一條金科玉律。如果遵守這條規(guī)律,那將會(huì)很安全。在很多情況下,我們必須問自己幾個(gè)簡(jiǎn)單的問題:
這條輸入數(shù)據(jù)足夠安全嗎?
對(duì)它進(jìn)行過濾了嗎?
我們遵循任何具體框架的規(guī)則和最佳實(shí)踐了嗎?
WordPress使用了PHP的vsprintf函數(shù),用于在$wpdb->prepare()函數(shù)中提前準(zhǔn)備好SQL statement,這意味著SQL語(yǔ)句使用格式化字符串和輸入值作為參數(shù)。這使我們得出結(jié)論:將用戶的輸入提供給格式化字符串從來不是一個(gè)好主意,因?yàn)樗赡軟]有對(duì)字符串進(jìn)行過濾,可能會(huì)包含有效的sprintf/printf指令。
這就是為什么這個(gè)方法,get_term_ids_for_tags()引起了我們的注意:
上面的代碼可以在下面的路徑中發(fā)現(xiàn):
nextgen-gallery/products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php
在這個(gè)源代碼中,我們注意到“$container_ids”字符串是由tag輸入創(chuàng)建的,并且它的值并沒有經(jīng)過適當(dāng)?shù)倪^濾。對(duì)于SQL注入,它是安全的,但是,它不能阻止任意格式化字符串指令/輸入的插入,在WordPress數(shù)據(jù)庫(kù)的$wpdb->prepare()方法下會(huì)引起問題。
$wpdb->prepare和sprintf
在prepare()方法的代碼中,我們注意到原始SQL代碼在執(zhí)行前發(fā)生了一些變化,具體變化是:如果在語(yǔ)句中發(fā)現(xiàn)%s,會(huì)被替換成‘%s’。同樣,我們看到在發(fā)生變化之后,它會(huì)被傳遞給vsprintf函數(shù),這意味著我們注入的任何有效的格式化字符串將有可能被處理。從PHP的sprintf函數(shù)文檔中我們知道可能會(huì)發(fā)生參數(shù)交換,當(dāng)沒有適當(dāng)過濾的輸入數(shù)據(jù)添加到格式化字符串時(shí),有可能導(dǎo)致類似于下面的一些問題:
1.惡意用戶將下面的輸入注入到格式化字符串/查詢中:
2.生成的查詢有可能類似于這樣:
3.當(dāng)傳遞給prepare()方法時(shí),有可能會(huì)被修改為:
(%s將會(huì)變成‘%s’)。
4.于是,當(dāng)由此產(chǎn)生的格式化字符串傳遞給vsprintf函數(shù)后,產(chǎn)生的SQL查詢語(yǔ)句具有以下格式:
如上所示,這意味著我們保留了一個(gè)額外的‘符號(hào),這打破了我們字符串的單引號(hào)序列,并會(huì)將我們生成的[any_text2]字符串變成SQL查詢的一部分。
利用方案
在插件的源代碼中,我們發(fā)現(xiàn)有兩個(gè)地方的函數(shù)會(huì)創(chuàng)建“$container_ids”字符串,分別是:
當(dāng)使用標(biāo)簽庫(kù)的短碼時(shí)。它需要一個(gè)特權(quán)認(rèn)證用戶來執(zhí)行這個(gè)攻擊。
當(dāng)從一個(gè)“NextGEN Basic TagCloud”相冊(cè)訪問標(biāo)簽時(shí),惡意訪問者可以通過稍微修改相冊(cè)的URL(網(wǎng)站中存在的相冊(cè)),去發(fā)起攻擊。
有了這些知識(shí),一個(gè)未經(jīng)授權(quán)的攻擊者可以向SQL查詢中添加額外的sprintf/printf指令,并利用$wpdb->prepare()的行為向執(zhí)行的語(yǔ)句中添加攻擊者控制的代碼。
最終的攻擊載荷(使用了TagCloud方法)類似于下面這樣:
(http://target.url/2017/01/17/new-one/nggallery/tags/test%1$%s)) or 1=1#)
或者(http://target.url/2017/01/17/new-one/nggallery/tags/test%1$%s)) or 1=2#)
結(jié)論
這是一個(gè)嚴(yán)重漏洞,如果你使用了該插件的一個(gè)有漏洞的版本,請(qǐng)盡可能快的對(duì)它進(jìn)行升級(jí)。