/*******************************************************************************
*
*  xcte.c - Extract Chunked Transfer-Encoding from TCP stream files
*
*  Copyright (C) 2010 - Christian North
*
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define version  "v0.2 BETA"

/******************************************************************************/
void usage()
{
	printf("XCTE %s - ",version);
	printf("Extract Chunked Transfer-Encoding from TCP stream files\n");
	printf("Usage: xcte <file>\n");
	exit(0);
}

/******************************************************************************/
int chunked_encoding(FILE *stream)
{
	const char *encoding="Transfer-Encoding: chunked";
	size_t len=1024;
	char data[len];
	long offset=0;
	int bytes=0;
	int c=0;

	while(!feof(stream)){
		if((bytes=fread(data,1,len,stream)) == 0) break;
		for(c=0;c<(bytes-1);c++){
			if(data[c] == 0x0D && data[c+1] == 0x0A){
				data[c]='\0';	
				offset+=strlen(data)+2;
				break;
			}
		}
		if(strstr(data,encoding) != NULL) {
			rewind(stream);
			return 1;
		}
		fseek(stream,offset,SEEK_SET);
	}

	return 0;
}

/******************************************************************************/
FILE *disposition(char *data)
{
	const char *disposition = "Content-Disposition";
	const char *filename = "filename=";
	FILE *fp = NULL;

	if(strstr(data,disposition) != NULL) {
		filename=strtok(data,"=");
		printf("Extracting Content: ");
		printf("%s\n",data+strlen(filename)+1);
		fp=fopen(data+strlen(filename)+1,"a");
		return fp;
	}

	return NULL;
}

/******************************************************************************/
int extract(FILE *stream, FILE *content)
{
	size_t chunk=0;
	size_t len=8;
	char *fragment;
	char data[len];
	char hex[len];

	while(!feof(stream)){
		if(fread(data,1,len,stream) == 0) break;
		snprintf(hex,len,"%c%c%c%c",data[2],data[3],data[4],data[5]);
		chunk=strtoul(hex,NULL,16);
		if((fragment = malloc(chunk)) == NULL) break;
		if(fread(fragment,1,chunk,stream) == 0) break;
		fwrite(fragment,1,chunk,content);
		free(fragment);
	}

	fclose(content);
	return 0;
}

/******************************************************************************/
int main(int argc, char **argv)
{
	char *streamfile=NULL;
	FILE *stream=NULL;
	FILE *content=NULL;
	size_t len=1024;
	char data[len];
	long offset=0;
	int bytes=0;
	int c=0;

	if(argc != 2) usage();
	streamfile = argv[1];
	if((stream = fopen(streamfile,"r")) == NULL) usage();

	if(!chunked_encoding(stream)){
		printf("Transfer-Encoding: chunked - not found in ");
		printf("\"%s\"\n", streamfile);	
		exit(0);
	}

	while(!feof(stream)){
		if((bytes=fread(data,1,len,stream)) == 0) break;
		for(c=0;c<(bytes-1);c++){
			if(data[c] == 0x0D && data[c+1] == 0x0A) {
				data[c]='\0';	
				offset++;
				break;
			}
			offset++;
		}
		content = disposition(data);
		if(content != NULL) break;
		fseek(stream,offset,SEEK_SET);
	}

	offset--;
	fseek(stream,offset,SEEK_SET);

	while(!feof(stream)){
		if((bytes=fread(data,1,len,stream)) == 0) break;
		for(c=0;c<(bytes-4);c++){
			if(data[c]   == 0x0D && data[c+1] == 0x0A &&
			   data[c+2] == 0x0D && data[c+3] == 0x0A ){
				offset+=2; 
				fseek(stream,offset,SEEK_SET);
				extract(stream,content);
				fclose(stream);
				break;
			}
			offset++;
		}
	}

	return 0;
}
/******************************************************************************/


After compiling this with "gcc -o xcte xcte.c" I was able to extract the 
executables contained in both stream files that had references to "file.exe"

$ gcc -o xcte xcte.c

$ ./xcte C0A81781-1066-3B355B66-80
Extracting Content: file.exe

$ file file.exe
file.exe: PE32 executable for MS Windows (GUI) Intel 80386 32-bit

$ md5sum file.exe
5942ba36cf732097479c51986eee91ed  file.exe

$ rm file.exe

$ ./xcte C0A81781-1067-3B355B66-80
Extracting Content: file.exe

$ file file.exe
file.exe: PE32 executable for MS Windows (GUI) Intel 80386 32-bit

$ md5sum file.exe
5942ba36cf732097479c51986eee91ed  file.exe


The tail end of the checksum matches the hint for question #4.


===============================================================================

Q4.  As part of the infection, a malicious Windows executable file was 
     downloaded onto Ms. Moneymany’s system. What was the file’s MD5 hash? 
     Hint: It ends on -Y΄91ed‘.

A4.  5942ba36cf732097479c51986eee91ed

===============================================================================

Unfortunatelly I don't have a lot of experience with malware or packers so I 
turned to google and found a list of candidates.

Using hexdump against the executable file suggested the packer was UPX.

$ hexdump -C -n 1024 file.exe 
00000000  4d 5a 90 00 03 00 00 00  04 00 00 00 ff ff 00 00  |MZ..............|
00000010  b8 00 00 00 00 00 00 00  40 00 00 00 00 00 00 00  |........@.......|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 e8 00 00 00  |................|
00000040  0e 1f ba 0e 00 b4 09 cd  21 b8 01 4c cd 21 54 68  |........!..L.!Th|
00000050  69 73 20 70 72 6f 67 72  61 6d 20 63 61 6e 6e 6f  |is program canno|
00000060  74 20 62 65 20 72 75 6e  20 69 6e 20 44 4f 53 20  |t be run in DOS |
00000070  6d 6f 64 65 2e 0d 0d 0a  24 00 00 00 00 00 00 00  |mode....$.......|
00000080  2b 97 33 0a 6f f6 5d 59  6f f6 5d 59 6f f6 5d 59  |+.3.o.]Yo.]Yo.]Y|
00000090  ac f9 00 59 67 f6 5d 59  48 30 30 59 6d f6 5d 59  |...Yg.]YH00Ym.]Y|
000000a0  6f f6 5c 59 2c f6 5d 59  36 d5 4e 59 6c f6 5d 59  |o.\Y,.]Y6.NYl.]Y|
000000b0  48 30 33 59 67 f6 5d 59  48 30 27 59 6e f6 5d 59  |H03Yg.]YH0'Yn.]Y|
000000c0  48 30 21 59 6e f6 5d 59  48 30 25 59 6e f6 5d 59  |H0!Yn.]YH0%Yn.]Y|
000000d0  52 69 63 68 6f f6 5d 59  00 00 00 00 00 00 00 00  |Richo.]Y........|
000000e0  00 00 00 00 00 00 00 00  50 45 00 00 4c 01 03 00  |........PE..L...|
000000f0  96 25 99 4b 00 00 00 00  00 00 00 00 e0 00 03 01  |.%.K............|
00000100  0b 01 08 00 00 10 01 00  00 10 00 00 00 80 00 00  |................|
00000110  30 8f 01 00 00 90 00 00  00 a0 01 00 00 00 40 00  |0.............@.|
00000120  00 10 00 00 00 02 00 00  04 00 00 00 00 00 00 00  |................|
00000130  04 00 00 00 00 00 00 00  00 b0 01 00 00 10 00 00  |................|
00000140  00 00 00 00 02 00 00 04  00 00 10 00 00 10 00 00  |................|
00000150  00 00 10 00 00 10 00 00  00 00 00 00 10 00 00 00  |................|
00000160  c4 a2 01 00 78 00 00 00  84 a1 01 00 40 01 00 00  |....x.......@...|
00000170  00 a0 01 00 84 01 00 00  00 00 00 00 00 00 00 00  |................|
00000180  00 00 00 00 00 00 00 00  3c a3 01 00 0c 00 00 00  |........<.......|
00000190  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001e0  55 50 58 30 00 00 00 00  00 80 00 00 00 10 00 00  |UPX0............|
000001f0  00 00 00 00 00 04 00 00  00 00 00 00 00 00 00 00  |................|
00000200  00 00 00 00 80 00 00 e0  55 50 58 31 00 00 00 00  |........UPX1....|
00000210  00 10 01 00 00 90 00 00  00 02 01 00 00 04 00 00  |................|
00000220  00 00 00 00 00 00 00 00  00 00 00 00 40 00 00 e0  |............@...|
00000230  2e 72 73 72 63 00 00 00  00 10 00 00 00 a0 01 00  |.rsrc...........|
00000240  00 04 00 00 00 06 01 00  00 00 00 00 00 00 00 00  |................|
00000250  00 00 00 00 40 00 00 c0  00 00 00 00 00 00 00 00  |....@...........|
00000260  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000003d0  00 00 00 00 00 00 00 00  00 00 00 33 2e 30 34 00  |...........3.04.|
000003e0  55 50 58 21 0d 09 02 0a  48 ae 9d 34 9e c6 c6 02  |UPX!....H..4....|
000003f0  04 65 01 00 27 ff 00 00  00 42 01 00 26 02 00 2e  |.e..'....B..&...|
00000400


===============================================================================

Q5.  What is the name of the packer used to protect the malicious Windows 
     executable? Hint: This is one of the most popular freely-available packers 
     seen in ΄mainstream‘ malware.

A5.  UPX

===============================================================================

To answer question #6 I downloaded a copy of UPX and used it to decompress the 
executable "file.exe."

$ upx -d file.exe 
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2009
UPX 3.04        Markus Oberhumer, Laszlo Molnar & John Reiser   Sep 27th 2009

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
     82432 <-     68096   82.61%    win32/pe     file.exe

Unpacked 1 file.


$ md5sum file.exe
0f37839f48f7fc77e6d50e14657fb96e  file.exe


===============================================================================

Q6.  What is the MD5 hash of the unpacked version of the malicious Windows 
     executable file?

A6.  0f37839f48f7fc77e6d50e14657fb96e

===============================================================================

To find the last answer I needed to infect a Windows XP host and monitor where 
it tries to connect on the Internet.  VMWare proved to be an excellent tool
for this task.

I have an ESX server in my home lab that I used to create a new resource 
pool called "forensics".  In this resource pool I created 2 virtual machines.
One running linux with a Apache and a copy of my IP traffic analyzer. The other 
running Windows XP.  These systems where isoloated from the Internet but 
connected to each other.  The Linux host was configured as the gateway for the
Windows system. Next I placed a copy of file.exe in the the default web root 
of the Linux server running Apache. On the Windows host I downloaded 
file.exe from the Linux server using a web browser.  Then I started my IP 
traffic analyzer on the Linux host to monitor all network communications from 
the Windows host.  On the Windows host I opened "file.exe" and monitored the 
output of the traffic analyzer on the Linux machine.  Immediately a connection 
attempt was made to 213.155.29.144 on TCP/444.

===============================================================================

Q7   The malicious executable attempts to connect to an Internet host using an 
     IP address which is hard-coded into it (there was no DNS lookup). What is 
     the IP address of that Internet host?

A7.  213.155.29.144

===============================================================================

This was a great puzzle!

I had fun honing my forensic skills and learned a lot in the process.   :) 


Additional Text:
/*******************************************************************************
*
*  xcte.c - Extract Chunked Transfer-Encoding from TCP stream files
*
*  Copyright (C) 2010 - Christian North
*
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define version  "v0.2 BETA"

/******************************************************************************/
void usage()
{
	printf("XCTE %s - ",version);
	printf("Extract Chunked Transfer-Encoding from TCP stream files\n");
	printf("Usage: xcte <file>\n");
	exit(0);
}

/******************************************************************************/
int chunked_encoding(FILE *stream)
{
	const char *encoding="Transfer-Encoding: chunked";
	size_t len=1024;
	char data[len];
	long offset=0;
	int bytes=0;
	int c=0;

	while(!feof(stream)){
		if((bytes=fread(data,1,len,stream)) == 0) break;
		for(c=0;c<(bytes-1);c++){
			if(data[c] == 0x0D && data[c+1] == 0x0A){
				data[c]='\0';	
				offset+=strlen(data)+2;
				break;
			}
		}
		if(strstr(data,encoding) != NULL) {
			rewind(stream);
			return 1;
		}
		fseek(stream,offset,SEEK_SET);
	}

	return 0;
}

/******************************************************************************/
FILE *disposition(char *data)
{
	const char *disposition = "Content-Disposition";
	const char *filename = "filename=";
	FILE *fp = NULL;

	if(strstr(data,disposition) != NULL) {
		filename=strtok(data,"=");
		printf("Extracting Content: ");
		printf("%s\n",data+strlen(filename)+1);
		fp=fopen(data+strlen(filename)+1,"a");
		return fp;
	}

	return NULL;
}

/******************************************************************************/
int extract(FILE *stream, FILE *content)
{
	size_t chunk=0;
	size_t len=8;
	char *fragment;
	char data[len];
	char hex[len];

	while(!feof(stream)){
		if(fread(data,1,len,stream) == 0) break;
		snprintf(hex,len,"%c%c%c%c",data[2],data[3],data[4],data[5]);
		chunk=strtoul(hex,NULL,16);
		if((fragment = malloc(chunk)) == NULL) break;
		if(fread(fragment,1,chunk,stream) == 0) break;
		fwrite(fragment,1,chunk,content);
		free(fragment);
	}

	fclose(content);
	return 0;
}

/******************************************************************************/
int main(int argc, char **argv)
{
	char *streamfile=NULL;
	FILE *stream=NULL;
	FILE *content=NULL;
	size_t len=1024;
	char data[len];
	long offset=0;
	int bytes=0;
	int c=0;

	if(argc != 2) usage();
	streamfile = argv[1];
	if((stream = fopen(streamfile,"r")) == NULL) usage();

	if(!chunked_encoding(stream)){
		printf("Transfer-Encoding: chunked - not found in ");
		printf("\"%s\"\n", streamfile);	
		exit(0);
	}

	while(!feof(stream)){
		if((bytes=fread(data,1,len,stream)) == 0) break;
		for(c=0;c<(bytes-1);c++){
			if(data[c] == 0x0D && data[c+1] == 0x0A) {
				data[c]='\0';	
				offset++;
				break;
			}
			offset++;
		}
		content = disposition(data);
		if(content != NULL) break;
		fseek(stream,offset,SEEK_SET);
	}

	offset--;
	fseek(stream,offset,SEEK_SET);

	while(!feof(stream)){
		if((bytes=fread(data,1,len,stream)) == 0) break;
		for(c=0;c<(bytes-4);c++){
			if(data[c]   == 0x0D && data[c+1] == 0x0A &&
			   data[c+2] == 0x0D && data[c+3] == 0x0A ){
				offset+=2; 
				fseek(stream,offset,SEEK_SET);
				extract(stream,content);
				fclose(stream);
				break;
			}
			offset++;
		}
	}

	return 0;
}
/******************************************************************************/

