Skip to content

Nosebleed

This is not real software. It is intentionally vulnerable.

It serves no real purpose and should not be used as anything other than a simple demonstration of what can happen if you trust user input.

If you want to use it, contact me (csx239@coventry.ac.uk) to get access to the source code. What is presented here is not actually what is used in the container - the "live" version will always give some leaked credentials. The code here is intended to be used for learners to read and identify potential exploitable assumptions.

Purpose

Nosebleed is a simple watchdog service.

It recieves input on a given port (usually 8259) and can respond to the folowing commands:

  • pingNxxxx - sends back the string xxxx of length N (for checking liveness and turnaround times)
  • time - sends back the time

Source Code

nosebleed_server.c

#include "nosebleed_utils.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h> 

#define PORT 8259
#define BUFFERSIZE 1024


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

  //Buffer to store data recieved
  char* buffer=allocateBuffer(BUFFERSIZE); 
  zero(buffer,BUFFERSIZE);

  //file descriptors for listening and the actual connection
  int listenfd = 0, connfd = 0;

  //Struct used to store address/port data, etc
  struct sockaddr_in serv_addr;  

  //Make the scket (internet, tcp)
  listenfd = socket(AF_INET, SOCK_STREAM, 0);

  //Blank out the struct ready for data
  memset(&serv_addr, '0', sizeof(serv_addr)); 


  //Fill in the server details struct
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  serv_addr.sin_port = htons(PORT); 

  //"bind" details from struct to file descriptor
  bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

  //accept conneections
  listen(listenfd, 10); 
  printf("Listening for connections on port %d\n.",PORT);
  while(1){
    zero(buffer,BUFFERSIZE);

    //wait for connection
    connfd = accept(listenfd, (struct sockaddr*)NULL, NULL); 

    //read data
    //Read up to BUFFERSIZE, prevent buffer overlflow
    read(connfd,buffer, BUFFERSIZE); 

    if(strncmp(buffer,"time",4)==0){  //Check if first 4 chars are "time"
      time_t now= time(NULL);
      //snprintf is like sprintf, but length limited to avoid buffer overflows...
      //(sprintf is like printf but writes to a buffer instead of the screen)
      snprintf(buffer, BUFFERSIZE, "%.24s\r\n", ctime(&now));  

      //Uee strlen to find the end of the time.
      //It will be null-terminated, so strlen can tell
      write(connfd, buffer, strlen(buffer)); 
    }else if(strncmp(buffer,"ping",4)==0){
      //The word "ping" will be followed by an integer representing
      //the length of the string being sent
      //Need to work out where the digits of the number start and stop, then
      //convert it to a number. This number is how many bytes/chars the word is
      int start=4; //integer starts here
      int end=start; //end needs to be worked out
      while(end<BUFFERSIZE && buffer[end]>='0' && buffer[end]<='9')
    end++;
      if(end>start){
    printf("Number starts at %d and ends at %d\n",start,end);
    char len_s[1+end-start];
    memcpy( len_s, &buffer[start], end-start );
    len_s[end-start] = '\0';
    int len_i=atoi(len_s);
    printf("The number is [%d]\n",len_i);
    //Now send it back...
    //Add 4+(end-start) to skip the ping word and number
    write(connfd,(buffer+4+(end-start)),len_i); 
      }

    }


    close(connfd);


  }

  free(buffer);

  return 0;
}

nosebleed_utils.c

#include "nosebleed_utils.h"
#include <string.h>
#include <stdlib.h>


void zero(char* buff, int len){
  //Zero the buffer so no left-over stuff gets sent back
  //Important security stuff right there.
  memset(buff, '0', len); 
}

char* allocateBuffer(int len){
  char*b= (char*)malloc(len*sizeof(char));
  return b;


}