/* SETICE Shellcode Execution Trace Intrusion Countermesure*
POC tool , see README , cheers ea , anikolic@phearless.org*/



#define MTU 65535 // Maximum Transmision Unit
#define TCP_PROTOCOL 6 
#define ORIG_EAX 11 // not defined anymore

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <malloc.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netpacket/packet.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <linux/user.h>
#include <sys/syscall.h>

int sock;
char INTERFACE[10];

struct sockaddr_ll from;
struct ethhdr *eth;
struct iphdr *ip;
struct tcphdr *tcp;
struct udphdr *udp;
struct icmphdr *icmp;
struct tm *lt;
time_t tt;

char buffer[MTU];
char *buff;
unsigned int received;
int ethlen;

int data_len;
int i;
struct ifreq ifr;


void setenvar (char *buff1) /* Function that puts the data of the package into an environment variable called */ 
{			    /* SHELLCODE laetr used by the tchild program to execute its content              */
  char tempstore[MTU];
  sprintf (tempstore, "SHELLCODE=%s", buff1);
  putenv (tempstore);
}

tracing (char *data_to_test) /* The actual place where all the magic happens. The function actualy doing the */
{			     /* detection 								     */
 
  int i;
  int sysno;
  pid_t child;
  int status;

  setenvar (data_to_test);	
  child = fork ();		
  if (child == 0)
    {
      setgid(getgid());
      setuid(getuid());
      ptrace (PTRACE_TRACEME, child, NULL, NULL); // seting the tchild into traced mode 
      execl ("./tchild", "tchild", NULL);         // executing the tchild proces to trace
      
    }
  else
    {
      for (i = 0; i < 1000; i++)
	
	{
			
	  wait (NULL);
		
	  sysno = ptrace (PT_READ_U, child, 4 * ORIG_EAX, 0); // ptrace part that reads the syscall number
	  if (sysno == -1) 					//as i sad before if -1 there is no shellcode 
	    {
                ptrace(PTRACE_KILL, child , NULL, NULL); // terminate the child 
		kill(child,SIGKILL);   			 // terminate it again (some unexplained problems) 
		return 0;
	    }
	  if (i < 17)
	    {
	      ptrace (PTRACE_SYSCALL, child, NULL, NULL); /* as sad before , standard syscalls child calls */ 
	      wait (NULL);                                /* are being skipped                             */
	      ptrace (PTRACE_SYSCALL, child, NULL, NULL);
	    }
	  else
	    {
	      ptrace(PTRACE_KILL, child , NULL, NULL); 	// terminate the child  
	      kill(child,SIGKILL); 			// terminate it again (some unexplained problems) 
              printf ("SHELLCODE DETECTED!!!\n"); 	// if ptrace returned syscall number alert
	      return 0;
	    }

	
	}
    }
	ptrace(PTRACE_KILL, child , NULL, NULL);	// terminate the child   
  	kill(child,SIGKILL); 				// terminate it again (some unexplained problems) 
	return 0;
}


char *network_to_string (unsigned long adress) // selfexplainable 
{
  char network_to_str_ret[16];
  char *ret;
  int a, b, c, d;

  a = adress / 16777216;
  adress = adress % 16777216;
  b = adress / 65536;
  adress = adress % 65536;
  c = adress / 256;
  adress = adress % 256;
  d = adress;

  sprintf (network_to_str_ret, "%d.%d.%d.%d", d, c, b, a);

  ret = malloc (16);
  memset (ret, '\0', sizeof (network_to_str_ret));
  strcpy (ret, network_to_str_ret);

  return ret;
}

void exiting ()
{
  close (sock);
  exit (0);
}


void recived_tcp () // function procesing the recived TCP packet
{
  char hex;
  tcp = (struct tcphdr *) (buffer + ethlen + sizeof (struct iphdr));
  printf
    (" Protokol:TCP \n Adresa slanja:%s\n Port slanja:%d\n Adresa prijema:%s\n Port prijema:%d\n",
     network_to_string (ip->saddr),
     ntohs (tcp->source),
     network_to_string (ip->daddr), 
     ntohs (tcp->dest));

  data_len = 
    ntohs (ip->tot_len) - sizeof (struct iphdr) - sizeof (struct tcphdr);
  buff = (buffer + ethlen + sizeof (struct iphdr) + sizeof (struct tcphdr));
  for (i = 0; i < data_len; i++)
    {
      tracing (buff); //calling the tracing function with data to test
      buff++;
    }

  printf ("\n");
}




void recived_unknown () // If unknown protokol packet recived, handle it
{
  tcp = (struct tcphdr *) (buffer + ethlen + sizeof (struct iphdr));
  printf (" Protokol:Nepoznat\n Adresa slanja:%s\n Adresa prijema:%s\n  ",
	  network_to_string (ip->saddr), network_to_string (ip->daddr));
  printf ("\n");
}

void recive_packets () // function actualy capturing packets and determining ther type 
{
  if (!strcmp ("lo", INTERFACE) || !strcmp ("eth0", INTERFACE))
    ethlen = sizeof (struct ethhdr);
  else
    ethlen = 0;

  received = sizeof (from);

  while (1)
    {
      memset (buffer, '\0', sizeof (buffer));
      received =
	recvfrom (sock, buffer, sizeof (buffer), 0,
		  (struct sockaddr *) (&from), &received);

      tt = time (0);
      lt = localtime (&tt);

      if (from.sll_pkttype == PACKET_OUTGOING && !strcmp (INTERFACE, "lo"))
	{
	  continue;
	}

      printf (" Datum: %02d-%02d-%4d \n Vreme: %02d:%02d:%02d \n",
	      lt->tm_mday, lt->tm_mon + 1, lt->tm_year + 1900,
	      lt->tm_hour, lt->tm_min, lt->tm_sec);

      ip = (struct iphdr *) (buffer + ethlen);


      switch (ip->protocol)
	{
	case TCP_PROTOCOL:
	  recived_tcp ();
	  break;
	default:
	  recived_unknown ();

	}
    }
}


int main (int argc, char **argv)
{

  printf ("\n");
  printf ("[+]---------------------------------------------------------\n");
  printf ("[+] SETICE - Shellcode Execution Trace Intrusion Countermesure\n");
  printf ("[+]           Coded by  Aleksandar Nikolic aka Wintermuth            \n");
  printf
    ("[+]    .: mail 2: anikolic [at] phearless dot org :.      \n\n");
  if (argc != 2)
    {
      printf ("Usage:\n %s interface \n Example:\n%s eth0 \n", argv[0],
	      argv[0]);
      printf
	("[+]---------------------------------------------------------\n");
      exit (0);
    }
  if (strlen (argv[1]) > 9)
    {
      printf ("[+] Too long interface name.\n");
      printf
	("[+]---------------------------------------------------------\n");
      exit (0);
    }
  strcpy (INTERFACE, argv[1]);
  printf ("[+]SETICE works on %s interface.                  \n",
	  INTERFACE);
  printf ("[+]---------------------------------------------------------\n");
	if (geteuid() > 0) 
	{
		printf("Program needs root privs tp work. \n");
		exit(0);
	}
	

  struct sockaddr_ll sockll;

  signal (SIGSEGV, exiting);
  signal (SIGTERM, exiting);
  signal (SIGQUIT, exiting);
  signal (SIGKILL, exiting);
  signal (SIGINT, exiting);
  signal (SIGHUP, exiting);



  sock = socket (PF_PACKET, SOCK_RAW, htons (ETHERTYPE_IP));


  if (sock < 0)
    {
      perror ("socket");
      exit (-1);
    }


  memset (&ifr, '\0', sizeof (ifr));
  strncpy (ifr.ifr_name, INTERFACE, sizeof (ifr.ifr_name));

  if (ioctl (sock, SIOCGIFINDEX, &ifr) < 0)
    {
      perror ("ioctl(SIOCGIFINDEX)");
      exit (-1);
    }


  memset (&sockll, '\0', sizeof (sockll));
  sockll.sll_family = PF_PACKET;
  sockll.sll_ifindex = ifr.ifr_ifindex;
  sockll.sll_protocol = htons (ETH_P_ALL);

  if (bind (sock, (struct sockaddr *) &sockll, sizeof (sockll)) < 0)
    {
      perror ("bind");
      exit (-1);
    }

  recive_packets ();


  exit (0);
}
 
