利用在一個流行的wordpress插件上發現的漏洞進行攻擊可以很輕而易舉的攻陷全球成千上萬的網站,比如最近的WP GDPR Compliance。一個插件出現漏洞則代表著所有使用這個插件的網站都存在巨大風險。但是能不能在wordpress圈子內找到一個比一個流行插件漏洞更具有攻擊性的漏洞呢?這就是這篇文章的主要內容。本文將介紹研究人員今年五月份在wordpress上發現的一個具有蠕蟲特性的存儲XSS漏洞的過程
事件簡介
WordPress.org掌管著wordpress cms所使用的所有插件和主題倉庫。此外,它還管理著主題/插件開發者用于修改代碼的賬號。在今年的五月份,研究人員在wordpress.org上發現了一個具有蠕蟲特性的存儲XSS漏洞。漏洞點出現在上文所提到的倉庫中的插件版本編號處。因此任何一個插件開發者都擁有實現本次XSS攻擊的條件。
研究人員在開發coderisk.com網站時檢測到該漏洞(他們的工作是為wordpress每一個插件的版本進行排序,因此注意到這個漏洞)。他們通過自己的一個插件對該漏洞進行了驗證。在下文當中,將會講述漏洞成因以及它是如何影響其他插件的用戶。
技術細節
因為wordpress.org的開源性,我們得以通過代碼審計來判斷該漏洞存在的可能性。
WordPress.org使用wordpress CMS構建。在官網上展示的插件內容只是一個模板文件所生成的,插件開發者無法通過操作來通過展示的內容影響官網的安全性。
插件開發者不與官網直接交互,而是通過SVN來完成修改插件文件,更新插件等等操作。當一個插件開發者通過了wordpress的審核后,他就擁有了與SVN交互的能力,可以通過獲得的SVN地址來對他的插件進行修改等。這里所獲得的權限相當于他獲得了wordpress.org開發者用戶賬號一樣。wordpress官網上的插件信息(比如插件名,插件描述,插件版本等)通過插件的readme.txt和插件php主文件獲取。官網將會時刻關注插件倉庫的變化以便于及時更新插件的數據。
我們發現這個漏洞的原因是在版本號輸出到倉庫的插件頁面前并沒有做任何的過濾處理。
下面的代碼展示了版本號是如何輸出的
wordpress.org/public_html/wp-content/plugins/plugin-directory/widgets/class-meta.php
第43行 <li><?php printf( __( 'Version: %s', 'wporg-plugins' ),
第44行 '<strong>' . get_post_meta( $post->ID, 'version', true ) . '</strong>' ); ?></li>
如同上文所說,在倉庫里,插件通過特定的模板展示它的信息。插件的其他信息,比如版本號,會作為meta data插入到模板中展示。
下面的代碼則展示了版本號從數據庫中取出并沒有經過任何的過濾和清洗就輸出了。那么現在,如果版本號在存儲到數據庫前也沒有進行任何的過濾的話,則存儲型XSS存在。而版本號是從插件的php主文件的一個特別的header中讀出。
wordpress.org/public_html/wp-content/plugins/plugin-directory/cli/class-import.php
第56行 namespace WordPressdotorgPlugin_DirectoryCLI;
第57行 ?
第58行 class Import {
第59行 ?
第60行 public function import_from_svn( $plugin_slug ) {
第61行 ?
第62行 $data = $this->export_and_parse_plugin( $plugin_slug );
第63行 ?
第64行 $headers = $data['plugin_headers'];
第65行 ?
第66行 update_post_meta( $plugin->ID, 'version', wp_slash( $headers->Version ) );
正如我們從代碼中看到的一樣,方法WordPressdotorgPlugin_DirectoryCLIImport:import_from_svn()
(第60行)負責將SVN中的更改與存儲在插件倉庫中的數據同步。而方法export_and_parse_plugin()
(第62行)負責將插件的信息提取出來(從上文提到過的readme.txt和php主文件),并保存重要的更改。版本號作為元數據插入到變更中,最終被更新到官網上的插件介紹中。而在變更和保存的過程中,對于版本號只應用了wp_slash()方法,而這個方法沒有對XSS作任何保護。至此利用鏈完整
漏洞的危害
利用這個漏洞,需要一個開發者賬號。因為在wordpress上傳一個插件就可以獲取到開發者賬號了,因此該漏洞利用難度低。
攻擊者可以將payload插入到它的插件版本號中,每一個在官網的插件倉庫中瀏覽到該惡意插件的用戶都會被攻擊。那么這個漏洞的危害到底有多大呢?
我們來想象一下,一個有開發者權限的用戶可以在WordPress.org上添加其他賬號作為插件的貢獻者。這樣一來被添加的賬號會獲得對該插件SVN的完全控制權,從而可以修改插件的代碼。不僅如此,被添加的賬號還具有插件的訪問控制權限,可以刪除和添加其他賬號作為插件的貢獻者,比如可以不需要經過任何認證刪除插件的作者。
我們可以在payload中添加一些簡單的ajax來進行這樣的操作。攻擊者可以設計一個payload,使得當擁有開發者權限的用戶訪問受此XSS感染的插件頁面時,向被感染的用戶的插件添加一個賬號作為貢獻者。之后,攻擊者再利用這個秘密添加的貢獻者賬號,繼續將payload插入到本次被感染的插件的版本號中,從而進行下一輪的傳播。對于payload的首輪傳播可以在論壇上發布新插件(含payload的惡意插件)宣傳帖子進行。
另一個在admin儀表盤上的反射性XSS
在找到第一個漏洞后,我們使用RIPS 對WordPress.org代碼庫進行了掃描。發現了另一個在admin儀表盤上的反射性XSS漏洞。
wordpress.org/public_html/wp-content/plugins/plugin-directory/admin/tools/class-stats-report.php
第1行 public function show_stats() {
第2行 ?
第3行 if ( isset( $_POST['date'] ) && preg_match( '/[0-9]{4}-[0-9]{2}-[0-9]{2}$/', $_POST['date'] ) ) {
第4行 $args['date'] = $_POST['date'];
第5行 } else {
第6行 $args['date'] = '';
第7行 }
第8行 ?
第9行 $stats = $this->get_stats( $args );
第10行 ?
第11行 printf(
第12行 __( 'Displaying stats for the %1$d days preceding %2$s (and other stats for the %3$d most recent days).', 'wporg-plugins' ),
第13行 $stats['num_days'],
第14行 $stats['date'],
第15行 $stats['recentdays']
第16行 );
在上面代碼的第3行中,從$ _POST [‘date’]收到的用戶輸入用preg_match進行正則匹配。然后沒有經過其他轉移,直接輸出了這個從用戶接受的值(第14行)。而這里的正則匹配模式顯然缺了個^
使得可繞過構造payload,比如<script>alert(1)</script> 0000-00-00
總結
在本文中,我們介紹了在WordPress.org網站上發現的兩個漏洞。第一個是插件庫中一個嚴重的存儲型XSS,任何在插件庫中擁有插件的用戶都可以利用它。如果惡意攻擊者利用它,會造成嚴重的后果。第二個是wordpress.org/plugins admin儀表盤中反射型的XSS,它展示了正則表達式中的一個小疏忽也會導致一個大漏洞。
原文地址:https://blog.ripstech.com/2018/wordpress-org-stored-xss/