Archive for septembre 12th, 2007

Ntfs File Reference Number

Quand j’ai lu le dernier édito de Misc, je me suis dit, « Ca y est, il a craqué papy », parce que nous faire une intro dans laquelle il nous résume toute les conneries qu’il a maté à la tv pendant l’été ca craint un peu, heureusement qu’on a pas eu droit à fort-boyard ni intervilles sinon j’aurais dit qu’il était perdu pour de bon. Par contre, j’ai aussi vu qu’il y avait un hors-série Misc prévu pour fin septembre, ca a fait*tilt* dans ma tête, genre comme si je m’étais cogné la tête sur la cuvette des chiottes, mais oui MERDE! Faut que je termine mon article moi ! Il me reste quand même assez de temps (ou pas ?) pour que je vous parle d’une feature de win assez sympatique.

Je reversais tranquillement vite fait un petit tool, le nfi.exe, « Sector to File Mapping Program » (dispo ici) qui permet notamment de dumper la liste des fichiers du disque en l’appelant da la façon suivante :

C:ProgHackcNtfs>nfi.exe c:
[...]
File 28
WINDOWS
    $STANDARD_INFORMATION (resident)
    $FILE_NAME (resident)
    $OBJECT_ID (resident)
    $INDEX_ROOT $I30 (resident)
    $INDEX_ALLOCATION $I30 (nonresident)
        logical sectors 2561160-2561303 (0x271488-0x271517)
    $BITMAP $I30 (resident)

File 29
WINDOWSsystem32
    $STANDARD_INFORMATION (resident)
    $ATTRIBUTE_LIST (resident)
    $FILE_NAME (resident)
    $OBJECT_ID (resident)
    $INDEX_ROOT $I30 (resident)
    $BITMAP $I30 (resident)

File 30
WINDOWSsystem32config
    $STANDARD_INFORMATION (resident)
    $FILE_NAME (resident)
    $INDEX_ROOT $I30 (resident)
    $INDEX_ALLOCATION $I30 (nonresident)
        logical sectors 488288-488303 (0x77360-0x7736f)
    $BITMAP $I30 (resident)

Je me suis demandé comment ca marchait donc hop hop, on sort olly et ida puis on regarde dedans. En regardant, j’ai vu un truc de maladouf, un appel à l’API ZwOpenFile, sans nom de fichier ! HewW wtF ??? Par la suite, la même fonction ayant récupérer un handle sur le fichier, appelait ZwQueryInformationFile avec l’InformationClass sur FileNameInformation pour obtenir le nom du fichier, par exemple \\WINDOWS\\system32.

Après quelques recherches, j’ai remarqué que ZwOpenFile utilisait le flag, FILE_OPEN_BY_FILE_ID, on retrouve sa description dans la doc du WDK :
The file name that is specified by the ObjectAttributes parameter includes the 8-byte file reference number for the file. This number is assigned by and specific to the particular file system. If the file is a reparse point, the file name will also include the name of a device. Note that the FAT file system does not support this flag.

Il serait donc possible de retrouver un fichier, uniquement à partir de son « file reference number », humm mais c’est bon ça :] Alors, je n’ai pas envie de me faire chier, donc je vous laisse lire la description d’un File Reference Numbers celon le Windows Internals :
A file on an NTFS volume is identified by a 64-bit value called a file reference. The file reference consists of a file number and a sequence number. The file number corresponds to the position of the file’s file record in the MFT minus 1 (or to the position of the base file record minus 1 if the file has more than one file record). The file reference sequence number, which is incremented each time an MFT file record position is reused, enables NTFS to perform internal consistency checks.

Ok, c’est cool, le FRN est représenté sur 64 bits, le seul petit souci, c’est qu’après plusieurs essais, je me suis aperçu que ces derniers n’était pas linéaire, comprenez que si les FRN 49, 50, 51 sont valides, le FRN 52 ne l’est pas forcément, et ca c’est embêtant. De plus comment savoir quand on a finit d’énumérer tout les fichiers du disque ? Ca serait bien d’éviter d’énumérer tout les 2^64 possibilités quand même. Bref back to reverse, pour comprendre comment nfi.exe fait pour régler ces soucis.

Ce petit tool semble utiliser NtFsControlFile pour envoyer des IOCLT au driver NTFS, il utilise 2 types d’IOCT, FSCTL_GET_NTFS_VOLUME_DATA et FSCTL_GET_NTFS_FILE_RECORD. La description de FSCTL_GET_NTFS_FILE_RECORD sur la msdn est assez intéressante :
FSCTL_GET_NTFS_FILE_RECORD
This control code enumerates file identifiers in a downward fashion, and always returns a file record that is in use. This means that the file identifier returned by this control code may not be the same as the file identifier specified in the input buffer. For example, if file identifiers 1 through 9 and 15 are in use, file identifiers 10 through 14 are not in use, and the file record corresponding to file identifier 15 is requested, that file record is returned.

If the file records that correspond to file identifiers 10 through 14 are requested, then the file record corresponding to file identifier 9 is returned. If any of the file records corresponding to file identifiers 1 through 9 are requested, those file records is returned.

Donc si on utilise NtFsControlFile avec l’IOCTL FSCTL_GET_NTFS_FILE_RECORD, cette dernière va faire en sorte de nous « arrondir » le FRN que nous lui avons passé en paramètre, de plus NtFsControlFile renvoie une erreur si jamais nous essayons d’accéder à un FRN trop élevé. Si ce c’est pas beau ça :]

Bref, c’est toujours un bon petit tool contre les rootkits. Avant, il s’agissait surtout de cacher les fichiers au moment ou l’on demandait le contenu d’un dossier, on modifiait le retour de l’api NtQueryDirectoryFile par exemple pour que notre fichier n’apparaisse pas dans la liste. Maintenant c’est un petit plus compliqué, parce qu’on possède un handle sur le fichier, si l’on modifie le retour de NtQueryInformationFile en disant par exemple qu’il n’y a aucun fichier, c’est un peu grillé :)

La possibilité la plus simple que je vois est de vérifié que le nom du handle crée correspond oui ou non à un fichier qu’on désire planquer, en kernelland on pourrait mettre une complétion routine sur l’IRP_MJ_CREATE qui controlerait le nom du fichier représenté par le handle qui vient d’être crée. La completion routine renverra, STATUS_OBJECT_PATH_NOT_FOUND si le fichier a été ouvert avec son path ou bien STATUS_INVALID_PARAMETER si on a tenté de l’ouvrir avec son FRN. Bien évidemment il faudrait penser aussi vérifié d’ou provient le syscall pour éviter que notre rk ne puisse accéder aux fichiers qu’il cache, comme un fichier de log par exemple. Bref moi je vais mettre à jour mon rootkit :)

A noter qu’après test, le rootkit AK922 que j’ai reversé se fait owner par cette méhode ;)

Dernière précision, cette technique ne n’est pas capable d’énumérer les ADS. Franchement, si vous voulez avoir un file system rootkit puissant, le combo ADS + completion routine sur l’IRP_MJ_QUERY_INFORMATION avec un file system filter pour gérer les appels de NtQueryInformationFile avec la FileInformationClass, FileStreamInformation est quasiment imparable :)
Mais bon je dis ca mais il doit encore exister des tricks inconnu permettant de les détecter super facilement :]

Vous trouverez le code ici :
http://ivanlef0u.fr/repo/FRN.rar

ref:
http://msdn2.microsoft.com/en-us/library/aa364568.aspx
http://msdn2.microsoft.com/en-us/library/aa364569.aspx

1 comment septembre 12th, 2007


Calendar

septembre 2007
L Ma Me J V S D
« août   oct »
 12
3456789
10111213141516
17181920212223
24252627282930

Posts by Month

Posts by Category