CVE-2019-11580 Atlassian Crowd RCE漏洞復現
- 2019 年 10 月 6 日
- 筆記
0X1 漏洞概述
Atlassian Crowd和Atlassian Crowd Data Center都是澳大利亞Atlassian公司的產品。Atlassian Crowd是一套基於Web的單點登錄系統。該系統為多用戶、網路應用程式和目錄伺服器提供驗證、授權等功能。Atlassian Crowd Data Center是Crowd的集群部署版。
近日,研究人員發現Atlassian Crowd和Atlassian Crowd Data Center中存在輸入驗證錯誤漏洞。該漏洞源於網路系統或產品未對輸入的數據進行正確的驗證。受影響的產品及版本包括:Atlassian Crowd 2.1.x版本,3.0.5之前的3.0.x版本,3.1.6之前的3.1.x版本,3.2.8之前的3.2.x版本,3.3.5之前的3.3.x版本,3.4.4之前的3.4.版本;Atlassian Crowd Data Center 2.1.x版本,3.0.5之前的3.0.x版本,3.1.6之前的3.1.x版本,3.2.8之前的3.2.x版本,3.3.5之前的3.3.x版本,3.4.4之前的3.4.版本。
0X2 環境搭建
下載漏洞影響版本程式碼,這裡我們選擇3.4.3版本
https://product-downloads.atlassian.com/software/crowd/downloads/atlassian-crowd-3.4.3.zip
在Ubuntu中安裝好JDK環境,病配置好JAVA_HOME和JRE_HOME等環境變數,如下所示。
JAVA_HOME=/usr/share/jdk1.8.0_221/ JRE_HOME=/usr/share/jdk1.8.0_221/jre CLASS_PATH=.:$JAVA_HOME/lib:$JRE_HOME/lib PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin export JAVA_HOME JRE_HOME PATH
重啟系統使用java和javac命令測試即可。
將漏洞程式碼文件解壓之後移動到/var目錄下

修改crowd-init.properties 配置文件,設置主目錄
vi /var/crowd-3.4.3/crowd-webapp/WEB-INF/classes/crowd-init.properties

然後回到環境主目錄中啟動環境 ,執行啟動命令即可
./start_crowd.sh
瀏覽器訪問環境鏈接
http://ip:8095/
點擊安裝,在中間需要輸入license,去官網註冊個帳號獲取一個月的試用期即可,安裝完成之後即可登錄

環境搭建成功。
0X3 漏洞分析
安裝完成之後在插件目錄會有一些插件

漏洞發生在插件pdkinstall-plugin-0.4.jar中。查看其文件描述文件
<atlassian-plugin name="${project.name}" key="com.atlassian.pdkinstall" pluginsVersion="2"> <plugin-info> <version>${project.version}</version> <vendor name="Atlassian Software Systems Pty Ltd" url="http://www.atlassian.com"/> </plugin-info> <servlet-filter name="pdk install" key="pdk-install" class="com.atlassian.pdkinstall.PdkInstallFilter" location="before-decoration"> <url-pattern>/admin/uploadplugin.action</url-pattern> </servlet-filter> <servlet-filter name="pdk manage" key="pdk-manage" class="com.atlassian.pdkinstall.PdkPluginsFilter" location="before-decoration"> <url-pattern>/admin/plugins.action</url-pattern> </servlet-filter> <servlet-context-listener key="fileCleanup" class="org.apache.commons.fileupload.servlet.FileCleanerCleanup" /> <component key="pluginInstaller" class="com.atlassian.pdkinstall.PluginInstaller" /> </atlassian-plugin>
從中可以看出Java servlet類com.atlassian.pdkinstall.PdkInstallFilter是通過訪問/admin/uploadplugin.action調用的。因為該漏洞是通過任意插件安裝的RCE漏洞,所以研究人員決定分析下PdkInstallFilterservlet的源碼。
研究人員將pdkinstall-plugin導入到IntelliJ中,並開始分析doFilter()方法。
如果請求方法不是POST,就退出會返回錯誤:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletResponse res = (HttpServletResponse) servletResponse; if (!req.getMethod().equalsIgnoreCase("post")) { res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Requires post"); return; }
然後確定請求中是否含有multipart內容。Multipart內容是指含有一個或多個不同集合的數據。如果其中含有multipart內容就調用extractJar()方法來提取請求中發送的jar,否則調用buildJarFromFiles()方法並嘗試從請求中的數據中構建插件jar文件。
/ Check that we have a file upload request File tmp = null; boolean isMultipart = ServletFileUpload.isMultipartContent(req); if (isMultipart) { tmp = extractJar(req, res, tmp); } else { tmp = buildJarFromFiles(req); }
下面再看一下extractJar()方法。
private File extractJar(HttpServletRequest req, HttpServletResponse res, File tmp) throws IOException { // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); // Parse the request try { List<FileItem> items = upload.parseRequest(req); for (FileItem item : items) { if (item.getFieldName().startsWith("file_") && !item.isFormField()) { tmp = File.createTempFile("plugindev-", item.getName()); tmp.renameTo(new File(tmp.getParentFile(), item.getName())); item.write(tmp); } } } catch (FileUploadException e) { log.warn(e, e); res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unable to process file upload"); } catch (Exception e) { log.warn(e, e); res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to process file upload"); } return tmp; }
下面再看一下extractJar()方法。
首先,用ServletFileUpload的新對象來示例,然後調用parseRequest()方法並分析HTTP請求。該方法會處理HTTP請求的multipart/form數據流,並設置FileItems的列表為變數items。
對每個FileItems中的每個item,如果field名是以file_開始的,並且不是form field,就會創建和寫如上傳到磁碟空文件的文件。如果失敗,變數tmp就為空,如果成功,變數tmp中就含有寫入文件的路徑。然後返回doFilter()主方法。
if (tmp != null) { List<String> errors = new ArrayList<String>(); try { errors.addAll(pluginInstaller.install(tmp)); } catch (Exception ex) { log.error(ex); errors.add(ex.getMessage()); } tmp.delete(); if (errors.isEmpty()) { res.setStatus(HttpServletResponse.SC_OK); servletResponse.setContentType("text/plain"); servletResponse.getWriter().println("Installed plugin " + tmp.getPath()); } else { res.setStatus(HttpServletResponse.SC_BAD_REQUEST); servletResponse.setContentType("text/plain"); servletResponse.getWriter().println("Unable to install plugin:"); for (String err : errors) { servletResponse.getWriter().println("t - " + err); } } servletResponse.getWriter().close(); return; } res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing plugin file");
如果extractJar()成功,tmp變數就會被設置,並且不等於null。應用會嘗試用pluginInstaller.install()方法來安裝插件,並找到進程中的錯誤。如果沒有錯誤,伺服器就會響應200 OK和插件成功安裝的消息。否則,伺服器會響應400 Bad Request和Unable to install plugin的消息,以及引發安裝失敗的錯誤。
如果extractJar()方法失敗了,tmp變數就會被設置為null,伺服器會響應400 Bad Request和Missing plugin file消息。
0X4 漏洞利用
下載漏洞利用腳本
https://github.com/jas502n/CVE-2019-11580
使用腳本測試

通關瀏覽器訪問鏈接測試其他命令:


利用成功。
0X5 漏洞修復
升級到最新版
漏洞環境源碼和利用程式碼下載鏈接