drupal 7 ajax,【漏洞分析】CVE-2018-7600 Drupal 7.x 版本代码执行
閱讀:
8,003
CVE-2018-7600影響范圍包括了Drupal 6.x,7.x,8.x版本,前幾天8.x版本的PoC出來之后大家都趕緊分析了一波,然后熱度似乎慢慢退去了。兩天前Drupalgeddon2項目更新了7.x版本的exp,實際環境也出現了利用,下面就簡單來看一下
0x01 概述
CVE-2018-7600影響范圍包括了Drupal 6.x,7.x,8.x版本,前幾天8.x版本的PoC出來之后大家都趕緊分析了一波,然后熱度似乎慢慢退去了。兩天前Drupalgeddon2項目更新了7.x版本的exp,實際環境也出現了利用,下面就簡單來看一下
看到項目上這樣寫
Drupal < 7.58 ~ user/password URL, attacking triggering_element_name form & #post_render parameter, using PHP’s passthru function
提示了問題出在user/password路徑下,通過#post_render傳遞惡意參數,問題出現在triggering_element_name表單處理下
0x02 漏洞分析
我們從三個問題入手,為什么PoC發了兩個包,第二次請求為什么要帶上一個form_build_id,以及為什么選擇user/password這個入口
先分析第一個post,照例還是先看一下Drupal 7的表單處理流程,跟8版本不太一樣,但是入口還是相似的。
根據文檔描述,當我們提交一個表單(例如找回密碼)時,系統會通過form_builder()方法創建一個form
一系列預處理后,會由drupal_build_form
()方法創建一個表單,在第386行調用drupal_process_form()方法,
跟進drupal_process_form()方法,這時候默認的$form_state['submitted']為false
不滿足if條件,$form_state['submitted']被設置為true
于是進入這個分支,最終被drupal_redirect_form重定向
我們的目的是要讓系統緩存一個form_build_id,以便后面拿出來用。要想form被緩存,就得想辦法讓if ($form_state['submitted'] && !form_get_errors() && !$form_state['rebuild'])不成立,也就是說要使$form_state['submitted']為false
從而進入下面的drupal_rebuild_form
那么如何讓$form_state['submitted']為false呢?
在includes/form.inc第886行
$form = form_builder($form_id, $form, $form_state);
跟進form_builder方法,第1987行
當$form_state['triggering_element']['#executes_submit_callback']存在值的時候就為true,那么我們就想辦法讓這個值為空
往上看第1972行
如果沒有設置$form_state['triggering_element'],那么$form_state['triggering_element']就設置為第一個button的值,所以正常傳遞表單的時候$form_state['triggering_element']['#executes_submit_callback']就總會有值
現在問題來了,如何構造一個form能夠確保$form_state['triggering_element']['#executes_submit_callback']為空或者說不存在這個數組呢?
我們注意到第1864行
_form_builder_handle_input_element()方法對表單先進行了處理,跟進去看一下
第2144行
這里$form_state['triggering_element']被設置為$element,前提是滿足_form_element_triggered_scripted_submission()方法,繼續跟入
第2180行
這個方法的意思是說如果_triggering_element_value和$element的鍵值都相等的話,返回true
$form_state['triggering_element']賦值為$element,其中不含['#executes_submit_callback'],一開始的條件就成立了
根據PoC,我們傳入_triggering_element_name=name
看到進入這個分支,進入form_set_cache()方法
數據庫中插入緩存form_build_id
成功寫入緩存
接下去來看一下這個緩存有什么用
分析PoC的第二個包,請求參數是這樣q=file/ajax/name/%23value/form_build_id
form_build_id即我們上一個寫入數據庫的緩存表單
首先請求會進入includes/menu.inc的menu_get_item()方法,
$path即我們傳進去的q參數,經過一系列處理傳給menu_get_ancestors()方法,該方法把path重新組合成一堆router,也就是Drupal處理路由到具體url的傳參方式,最終被db_query_range()帶入數據庫查詢
我們關注查詢結果$router_item的page_callback值,因為這個值最終會作為參數被帶入call_user_func_array()
到這里就跟8版本的情況有點類似了
跟入回調函數file_ajax_upload()
還是一樣,把$form_parents完整取出賦值給$form,加上一些前綴后綴后最終進入drupal_render()方法
最終得到執行
到目前為止我們分析清楚了為什么PoC要發兩次包,以及第二次請求為什么要帶上一個form_build_id,現在來想一想為什么要請求user/password這個路徑呢?
在user這個module下的user_pass()方法
看到這里是不是感覺跟8版本很相似,#default_value從get的name參數里取值,而name可以作為數組傳入,它的屬性在下面正好可以被利用,一個巧妙的利用鏈就串起來了。
0x03 總結
Drupal 7.x的利用比8.x要復雜一些,但觸發點和一開始的風險因素還是類似的,一是接收參數過濾不當,而是可控參數進入危險方法。官方補丁把入口處的#全給過濾了,簡單粗暴又有效,估計再利用框架本身的特性想傳遞進一些數組或元素就很難了。
0x04 參考
https://github.com/dreadlocked/Drupalgeddon2
https://research.checkpoint.com/uncovering-drupalgeddon-2/
總結
以上是生活随笔為你收集整理的drupal 7 ajax,【漏洞分析】CVE-2018-7600 Drupal 7.x 版本代码执行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MT【91】空间余弦定理
- 下一篇: 计算机专业和机械自动化哪个好,自动化和机