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

.NET serialiception

Introduction

After discovering a weird base64 encoded format during pentest I wanted to find out what was that format and I met BinaryFormatter.

The BinaryFormatter format is internally used in a bunch of functions or can be used directly to materialize .NET objects.

The binary format is well documented here.

To be able to serialize and unserialize .NET objects, they must extend the ISerializable class.

As other serialization formats, the unserialized object is often casted to a specific one triggering some error if it doesn’t fit.

This research focus on the one that implements some specific deserialization constructors which are executed regardless of the expected casting.

James Forshaw already did a lot of work on this subject (https://media.blackhat.com/bh-us-12/Briefings/Forshaw/BH_US_12_Forshaw_Are_You_My_Type_WP.pdf) but firstly I wanted an easy way to tamper this BinaryFormatter format and then implement some POC everybody could use during penetration testing.

My scenario is to try to exploit this BinaryFormatter serialization from a web application. As I said, I saw it directly in POST and Cookies data during a pentest but another interesting vector is the ViewState that could pass BinaryFormatter format with the Token_BinarySerialized (even if I’m late on the subject http://fr.slideshare.net/ASF-WS/asfws-2014-slides-why-net-needs-macs-and-other-serialization-talesv20 as it’s rare to find one without a HMAC).

Firstly I wrote a JSON <-> BinaryFormatter converter so it’s easy to extract readable information from a BinaryFormatter stream, edit it in JSON and send back the modified version.

I quickly did the same with ViewState so I could tamper a non hmaced ViewState and insert my crafted BinaryFormatter to it.

Then I just have to find the interesting class.

ISerializable

Analysing most of the native ISerializable extended class, I noticed every actions an attacker could do by tampering a BinaryFormatter stream (I tried to be comprehensive).

Here is a list of quite interesting things we can do during deserialization :

Already known

Use examples/TempFileCollection_arbitrary_delete_or_smb_connect.json
ObjectId 8 is a BinaryObjectString which contains the filepath you want to delete (if you use a UNC path it will connect to it and leak hash)

Useless at the first view

Check examples/HashMembershipCondition_arbitrary_empty_ctor_call.json
ObjectId 4 contains a BinaryObjectString which contains the Assembly string of the class you want to construct.
This class should have an empty argument constructor that would be called (so it seems very useless)

I didn’t try it as I didn’t find an idea to exploit it.

  • Call to ParseManifest (unkown) ndp/clr/src/BCL/system/activationcontext.cs

I didn’t try it as I don’t know what Manifest is (maybe interesting)

  •  Unserialize Icon, Font, Bitmap, Cursor, ImageList

ndp/fx/src/commonui/System/Drawing/Icon.cs
ndp/fx/src/commonui/System/Drawing/Advanced/Font.cs
ndp/fx/src/commonui/System/Drawing/Bitmap.cs
ndp/fx/src/winforms/Managed/System/WinForms/Cursor.cs
ndp/fx/src/winforms/Managed/System/WinForms/ImageListStreamer.cs

Could be good to exploit native parser bug remotely.

  • Load X509 certificate ndp/clr/src/BCL/system/security/cryptography/x509certificates/x509certificate.cs

Interesting discoveries

DataSet object waits for XmlSchema BinaryObjectString that is vulnerable to Xml External Entities (check examples/DataSet_XXE.json).

Unfortunately Microsoft XML parser is quite susceptible so I didn’t succeed to blindly leak a web.config file (I only read C:\Windows\system.ini as POC). Actually I don’t know what to leak with a blind XXE on Windows System.

Maybe an XXE expert could do better, but it’s still a quite critical vulnerability if you know the application (SSRF and co…)

  • Unmarshal COMObject

So here comes the best part!

COMObject Marshaling

James Forshaw already pointed it ndp/fx/src/wmi/managed/System/Management/InteropClasses/WMIInterop.cs without trying to exploit it.

As COMObject Mashaling is a native windows function, I looked at the COMObject marshaling format to add a third layer of serialization (https://msdn.microsoft.com/en-us/library/cc226828.aspx) and reversed the ole32.dll CoUnmarshalInterface function.

I know nothing about COMObject so maybe I missed an easy exploit but I didn’t succeed to use OBJREF_STANDARD, OBJREF_HANDLER, and OBJREF_EXTENDED.

On the other hand OBJREF_CUSTOM allows you to pass an arbirary clsid that would load the associated DLL and try to unmarshall another layer of specific data pObjectData if this COMObject exposes the IMarshal interface (kind of 4th layer of custom serialization).

Unfortunately automatically trying junk data on every CLSID I found in the register didn’t produce anything.

Reversing ole32.dll shew me some special hardcoded CLSID. One of them  (CLSID_StdWrapper : {00000336-0000-0000-C000-000000000046}) used with special IID (IUnknown {00000000-0000-0000-C000-000000000046}) seems to use the pObjectData and fuzzing its format gives me a crash with controlled register \o/ !

I did my first tests on specific 64bits binaries under windows 7 and then setup a windows server 2008 R2 64 bits with IIS and asp.net 2.5 but the COMobject unmarshalling from BinaryFormatter is a feature of .NET (even in the last version) and the crash occurs in ole32.dll not related to IIS version so it should work everywhere.

crash_capture_20160512_103139

I figured that it may be possible to control RIP from this pointer with a very specific structure.

[Pointer + 0x20] -> [Pointer2 + 0x20] -> [Pointer3 + 0x28]
                                      -> [Pointer3 + 0x10]
                                      -> [Pointer3] == 0
[Pointer + 0x38] -> [Pointer4 + 0x38] -> [Pointer5] -> [Pointer6 + 8] -> RIP

Of course finding such specific structure in randomly mapped memories was impossible.

If you remember the list of possible unserializable .NET objects one of them should raise your attention to achieve heap spray.

Bitmap ! Indeed it is possible to craft a specific BMP that would be mapped untouched in memory (see examples/Image.json).
But how can we achieve heap spray without sending Gb of BMP?

BinaryFormatter allows internal object reference!

Firstly it may allow an easy DOS by cross referencing two objects (haven’t tested yet).

Secondly, it’s perfect to do a nice heap spray!

Just create one ArraySinglePrimitive with your BMP sprayed data and create as many ClassWithMembersAndTypes (System.Drawing.Image) with member “Data” a MemberReference pointing to the ObjectID of this ArraySinglePrimitive.

I choose an arbitrary bmp size aligned on 0x10000 ((640 * 818) == 0x180000 + bmp header) so it would reduce the shift in random mapping.

Once I found a nice always mapped address (0x30303030) I tried to spray the magic pointer allowing me to control RIP.

def q(i):
 return struct.pack('<Q', i)

spray =  q(0) + q(pointer+0x8)
spray += q(RIP-1) + q(0xDEADBABEDEFECA7E)
spray += q(pointer) + q(0xDEADBABEDEFECA7E)
spray += q(0xDEADBABEDEFECA7E) + q(pointer+0x10)

heap

A very good point for us is that memory access errors are handled by .net so spawned IIS worker process w3wp.exe doesn’t crash.

You can try as many times as you want and it should take maximum 8 tries to find your structure correctly aligned!

With relatively good RIP control, next part was to find non-ASLR DLL to construct our ROP.
Fortunately, diasymreader.dll is non-ASLR and seems to be loaded after a first .net exception.

I needed to change my magic pointer structure to also control RSP with one gadget and point it in my sprayed retchain+ropchain.

heaprop

spray =  q(0) + q(pointer+0x8)
spray += q(RIP-1) + q(0xDEADBABEDEFECA7E)
spray += q(pointer) + q(RIP2)
spray += q(RSP) + q(pointer+0x10)

RIP : push rsi # pop rsp # add rsp, 0x20 # pop rdi
RIP2 : pop rsp # add rsp, 0x10

This way I can control RSP !

Last part should be straight-forward as virtualAlloc and memcpy functions can be called from diasymreader.dll.

A third heapspray with nopsled+shellcode should be enough to stabilize the exploit.

heapsc

I successfully reliably exploited this vulnerability on my IIS lab directly from a non hmac’ed ViewState to run meterpreter.

To sum up :

  1. ViewState deserialization with Token_BinarySerialized
    If you directly find BinaryFormatter (with ot without obfuscation (SAP application I’m looking at you with your base64(gzip(base64(BinaryFormatter)))))
  2. BinaryFormatter deserialization which we use to deserialize 3 BMP 400 times each and a IWbemClassObjectFreeThreaded object
  3. this object actually contains a malicious marshalled COMobject that allows us to control a special pointer.
  4. if this pointer dereference a specific structure that we spray with our first BMP we can control RIP then RSP that point on our second BMP with a ROPCHAIN that VirtualAlloc and memcpy our shellcode from the third BMP.

Conclusion

Deserializing untrusted input is bad, we all know that… I didn’t find public POC of vulnerability with .NET serialization (compare to Java) so here it is!

For information, I reported the COMObject deserialization crash to Microsoft and they flagged it “defense in depth” as it requires untrusted unmarshaling first, so if they make a patch it will be in a long time.

Unfortunately I didn’t find another vector to exploit the COMObject unmarshaling bug (RPC DCOM use another dll to unmarshal COMObject) but maybe someone with better windows knowledge could find an idea !

Last but not least the .NET remoting system internally uses BinaryFormatter. It has been replaced by WCF but it should be possible to exploit the same bugs if WCF is configured to accept NetDataContractSerializer.

Defcon 2015 résolution heapsoffun

La semaine dernière, plusieurs ingénieurs de SCRT ont participé aux qualifications du CTF Defcon avec l’équipe 0daysober, qui a terminée 10ème et se qualifie donc pour la finale ! Ce post décrit deux des épreuves résolues, knockedup et heapsoffun.

Heapsoffun

If you have been knockedup then you know what to do. Perhaps try "tirer"
sha1sum heapsoffun 5ee5b2cde811e617cd789c73c1d8d2d9e8b27c36
Yes we know the flag is owned by root.

Un challenge pwnable de 4 points faisable après knockedup.

tldr; un challenge de reverse de 1 point permettant d’ouvrir 2 ports en fonction d’une séquence de paquets envoyée sur des ports UDP.

Continue reading Defcon 2015 résolution heapsoffun

Metasploit psexec resurrect

What a joy !

I just received tonight this nice email from github :

Meatballs1 merged commit 1a3b319 into  from 

My 2 years old pull request to metasploit was just accepted !

Long story short

Annoyed to have to chain msfencode and msfencode and msfencode to bypass anti-virus during penetration testing, we wanted to create some packers that do the job. Better than that, we wanted to integrate it in metasploit to use it with all the framework features and improve our performances :D.

I firstly figured it out that most of AVs detect ‘exe’ loader creation technique (from msfpayload) even if you put a “foobar” payload : echo -n “foobar” | msfencode -t exe -e generic/none => HIGH SCORE on virustotal.

I proposed “exe-only” technique. Shortly, it write the payload at the original entry-point of your exe template and put the section RWX so it reduces the loader signature to one RWX section only.

So next we could focus on the payload encoding.

For information, I scanned every native windows exe and find that ntkrnlpa.exe and ntoskrnl.exe contains RWX section (if AVs shoots files for having RWX sections, it would shoot Windows native exe too).

After some debate this exe-only technique was added to metasploit.

Next part was to use it with the famous psexec module that nobody use anymore because every AVs trigger it.

It’s simply because service executable created by psexec module use subsitution method, replacing “PAYLOAD:” with the payload in a template. Again, AVs trigger template regardless of the payload and to create a working template it was such a pain that we prefered use a “normal” executable and send it using psexec custom_exe feature…

So I wanted to use the previously merged “exe-only” technique to create a register service payload prepended to the user encoded payload.

That’s that stuff that took two years to land in Metasploit, mostly because I’m a noob in ruby and git (booo) and a little bit of scepticism from some metasploit guys.

Anyway, I’m proud it’s finally merged, you could just track it for fun :

07/09/2012 – https://dev.metasploit.com/redmine/issues/7231

14/10/2012 – https://github.com/rapid7/metasploit-framework/pull/903

19/05/2013 – https://github.com/rapid7/metasploit-framework/pull/1850

20/11/2013 – https://github.com/rapid7/metasploit-framework/pull/2657

07/06/2014 – Merged !

I hope you will re-use psexec now and I’m sure it bypass a lot of BIG AV at this moment because their sandbox executes the service PE that actually register itself to the SVC manager and exit. SVC manager then re run the PE beginning at the registered service entry-point.

It was very cool to speak with Metasploit guys and I know I would have to persevere for my next pull request !

Neo4j – “Enter the GraphDB”

Following interest for NoSQL (see MongoDB exploit :D), this time I wanted to check Neo4j, the famous Graph Database. As you can see on their blog http://blog.neo4j.org/, Neo4j is really active and updates come really often ! The v1 was released in 2010 and v2 in 2013 and I didn’t find any specific paper about security so it may be interesting… Don’t hesitate to correct me if I say something wrong ! Continue reading Neo4j – “Enter the GraphDB”