Thursday 18 August 2016

SPSE Pyhooks

Some time ago I was looking for the way of developing my own tools. Of course thinking on creating tools to attack web applications. After a quick search in google I found out the SecurityTube Python Scripting Expert Course which content was mainly in form of videos. Finally I decided to bet on the certification and here we are trying to go through the exam in just a couple of weeks.

I save my opinion about the course until I have actually finished. It is still some study and the exam pending for me.

Going to the point, one of the parts of the reversing course was attaching to an existent process by means of pyhooks. There are several different types of pyhooks being the most used during the course the ones of BPHook type.  You can extend the information on pyhooks here.

As one of the exercises in the mocked exam, we need to develop a script hooking to the bind function in certain .exe file. The objective of the pyhook is printing the IP and the port the .exe file is binding to.

This piece of code solves the problem:

#!/usr/bin/env python

import immlib
from immlib import LogBpHook
import struct
import socket

DESC = "Bind hook demo"

class DemoHook(LogBpHook):

    def __init__(self):
        LogBpHook.__init__(self)

    def run(self, regs):
               
        imm = immlib.Debugger()

                sockAddrIn = imm.readLong(regs['ESP'] + 8)
                port = struct.unpack("!H",imm.readMemory(sockAddrIn + 2,2))
                bindedIp = imm.readMemory(sockAddrIn + 4,4)
               
        imm.log("[+] Bind Function called.")
        imm.log("Port binded: %d" % port)
        imm.log("IP Address: %s" % str(socket.inet_ntoa(bindedIp)))
       
        #receivedStr = imm.readString(secondArg)
        #imm.log("Received String %s" % receivedStr)
       

def main(args):

    imm = immlib.Debugger()
    hookFunction = "ws2_32.bind"
    functAddress = imm.getAddress(hookFunction)
    newHook = DemoHook()
    newHook.add("Bind Hook", functAddress)

    return "Bind BPHooking"


Simple, isn't it?. Let see what is behind each LoC in this "small" pyhook

By default the bind function in Windows takes 3 arguments according to the documentation in here:

That three arguments are:
  • s [in]: A descriptor identifying an unbound 
  • socket.name [in]: A pointer to a sockaddr structure of the local address to assign to the bound socket .
  • namelen [in]: The length, in bytes, of the value pointed to by the name parameter.

So, we are interested in the second parameter as is the one including the local address.

It worths to mention that the stack grows from higher to lower positions in X86 systems and the parameters are introduced in the stack starting from the last one of them.

keeping it in mind we will find in memory just after the call the first parameter
in ESP+4, the second one in ESP+8 and the third one in ESP+12 (the first one included in the stack which is a LIFO structure).

And how it will look like? The structure is as follows:

struct sockaddr_in {
        short   sin_family;
        u_short sin_port;
        struct  in_addr sin_addr;
        char    sin_zero[8];
};


As you know, the infomation in the stack is not the parameter itself but the memory address where to find the parameter value. Therefore we need to read ESP + 8 where we will locate the memory address of the scokaddr_in structure.
As we want to print the port number, we need to read a short starting from that point + 2 memory positions (busy with the sin_family).

Another important consideration is that the information in memory for this parameter is stored in network byte order. We can use the "!" character in the format string to indicate we want to read form memory in this way or alternatively use ">" character since network order is equivalent to Big Endian.

According to the documentation in here you can find how the format string should be forged in order to read an unsigned short from a memory position and the number of bytes it will take up.

https://docs.python.org/2/library/struct.html

As a result we have already our variable containing the port number

Exactly following the same thinking we can come up with how to retrieve the
IP address from the stack... or maybe not. Again something missing. Even though we know an IPv4 address is 4 bytes we don't know if the struct in_addr has any other fields inside.

Another quick googling and we found out it looks like this:

https://msdn.microsoft.com/es-es/library/windows/desktop/ms738571(v=vs.85).aspx

typedef struct in_addr {
  union {
    struct {
      u_char s_b1,s_b2,s_b3,s_b4;
    } S_un_b;
    struct {
      u_short s_w1,s_w2;
    } S_un_w;
    u_long S_addr;
  } S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;


So what would we find in the memory address of sockAddrIn + 4? If we assume the server is using a code like the one in here:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx

we will find an unsigned long corresponding to the S_addr parameter. But the story doesn't end so fast. We need a function to translate the data recovered from memory to a string which can be understood and properly displayed. Our function is in the "socket" module and it is called inet_ntoa. Again we need to know this method is taking a PACKED IP address as parameter so we shouldn't to unpack the information in memory or it won't work. Reference in here:

https://docs.python.org/2/library/socket.html

That's it, we can just print confortably both parameters to the log. For running
the pyhook, as it has been developed as a pycommand it must be placed in the pycommands folder of immunity debugger. 

Another important aspect to take into account is that the bind call is called only once, after that one there is a loop calling accept in order to serve all the clients. That means the pyhook must be run before the .exe file executing the function call. The correct order is open the .exe file, execute the pyhook and then run the program.

++Security

No comments:

Post a Comment