Static Secure ARP UDP Broadcast Client/Server

0normal

2attacker

1attacked

3fixed

arp.c

/*

arm-linux-gnueabi-gcc -static -march=armv7 -o arp.arm arp.c ; chmod 700 arp.arm

./arp.arm "s" "br0" "/jffs/etc/freeradius/users" "10.0.0.20" "10.0.0.200"


gcc -Wall -o arp.xes arp.c ; chmod 700 arp.xes

read -p "pwd: " -s p ; echo ; echo "$p" | ./arp.xes "c" "en0"

*/

#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>

#include "sha256.c"

typedef struct userinfo {
	char *i;
	unsigned long t, l, a;
} infodata;

void strp(char *cstr, int clen)
{
	cstr[clen] = '\0';
	while ((clen > 0) && ((cstr[clen-1] == '\r') || (cstr[clen-1] == '\n')))
	{
		--clen;
	}
	cstr[clen] = '\0';
}

void safe(char *cstr)
{
	char *chrs = "0123456789ABCDEFabcdef.:";
	int x, y, l = strlen(cstr), m = strlen(chrs), flag;
	for (x = 0; x < l; ++x)
	{
		flag = 0;
		for (y = 0; y < m; ++y)
		{
			if (chrs[y] == cstr[x])
			{
				flag = 1;
			}
		}
		if (flag == 0)
		{
			cstr[x] = '0';
		}
	}
}

unsigned long ipvf(char *addr)
{
	unsigned long i = 0;
	char *p = NULL, *a = strdup(addr), *t = a;
	while (1)
	{
		p = strchr(a, '.');
		if (p != NULL) { *p = '\0'; }
		i = ((i << 8) + atoi(a));
		a = (p + 1);
		if (p == NULL) { break; }
	}
	free(t);
	return i;
}

int sign(char *pmsg, int size, unsigned long pres, char *skey)
{
	int x;
	char hash[SHA256_LENGTH*4];
	unsigned char hout[SHA256_LENGTH];
	SHA256_CTX hobj;
	
	snprintf(&(pmsg[strlen(pmsg)]), (size / 4) * sizeof(char), " %ld %s", pres, skey);
	
	SHA256_INIT(&hobj);
	SHA256_UPDATE(&hobj, (unsigned char *)pmsg, strlen(pmsg));
	SHA256_FINAL(&hobj, hout);
	for (x = 0; x < SHA256_LENGTH; ++x)
	{
		sprintf(&(hash[x*2]), "%02x", hout[x]);
	}
	hash[SHA256_LENGTH*2] = '\0';
	
	char *rptr = strrchr(pmsg, ' ');
	++rptr;
	strcpy(rptr, hash);
	rptr[SHA256_LENGTH*2] = '\0';
	
	return 0;
}

int vrfy(char *pmsg, int size, char *skey, char *sign, unsigned long rate, unsigned long pres, unsigned long last)
{
	int x;
	char hash[SHA256_LENGTH*4];
	unsigned char hout[SHA256_LENGTH];
	SHA256_CTX hobj;
	
	snprintf(&(pmsg[strlen(pmsg)]), (size / 4) * sizeof(char), " %ld %s", pres, skey);
	
	SHA256_INIT(&hobj);
	SHA256_UPDATE(&hobj, (unsigned char *)pmsg, strlen(pmsg));
	SHA256_FINAL(&hobj, hout);
	for (x = 0; x < SHA256_LENGTH; ++x)
	{
		sprintf(&(hash[x*2]), "%02x", hout[x]);
	}
	hash[SHA256_LENGTH*2] = '\0';
	
	if (strcmp(hash, sign) != 0) { return -1; }
	if ((time(NULL) - rate) < 3) { return -1; }
	if (pres <= last) { return -1; }
	
	return 0;
}

int find(infodata *objs, int l, char *i)
{
	int x;
	for (x = 0; x < l; ++x)
	{
		if (objs[x].i == NULL) { objs[x].i = strdup(i); return x; }
		if (strcmp(objs[x].i, i) == 0) { return x; }
	}
	return -1;
}

int uniq(infodata *objs, int l, int i, unsigned long a)
{
	int x;
	for (x = 0; x < l; ++x)
	{
		if ((x != i) && (objs[x].a == a))
		{
			return x;
		}
	}
	objs[i].a = a;
	return -1;
}

char *gnet(char *intf, char mode)
{
	char *info = "ifconfig '%s' | sed -e 's/HWaddr/ether/g' -e 's/addr://g' -e 's/Bcast:/broadcast /g' | %s > /tmp/arp.net";
	char *inet = "grep -i 'inet ' | sed -e 's/^.*inet[ ]*\\([^ ]*\\).*$/\\1/g'";
	char *maca = "grep -i 'ether ' | sed -e 's/^.*ether[ ]*\\([^ ]*\\).*$/\\1/g'";
	char *brod = "grep -i 'broadcast ' | sed -e 's/^.*broadcast[ ]*\\([^ ]*\\).*$/\\1/g'";
	char comd[2048];
	FILE *fobj;
	
	bzero(comd, 2048 * sizeof(char));
	
	if (mode == 'i') { snprintf(comd, 1024 * sizeof(char), info, intf, inet); }
	if (mode == 'm') { snprintf(comd, 1024 * sizeof(char), info, intf, maca); }
	if (mode == 'b') { snprintf(comd, 1024 * sizeof(char), info, intf, brod); }
	
	system(comd);
	
	fobj = fopen("/tmp/arp.net", "r");
	bzero(comd, 2048 * sizeof(char));
	fgets(comd, 1024 * sizeof(char), fobj);
	strp(comd, strlen(comd));
	fclose(fobj);
	
	return strdup(comd);
}

void serv(char **args)
{
	/* note: 256 ip address range limit */
	
	int x, y, rlen, sock, bron = 1;
	unsigned long aadr = ipvf(args[4]), badr = ipvf(args[5]), secs;
	char *iadr = gnet(args[2], 'i'), *madr = gnet(args[2], 'm');
	char pass[2048], mesg[2048], temp[2048], sarp[2048];
	infodata last[256];
	FILE *fobj;
	socklen_t slen;
	struct sockaddr_in sobj, cobj;
	
	for (x = 0; x < 256; ++x)
	{
		last[x].i = NULL; last[x].a = 0;
		last[x].t = time(NULL); last[x].l = 0;
	}
	
	sock = socket(AF_INET, SOCK_DGRAM, 0);
	setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bron, sizeof(bron));
	
	bzero(&sobj, sizeof(sobj));
	sobj.sin_family = AF_INET;
	sobj.sin_addr.s_addr = htonl(INADDR_ANY);
	sobj.sin_port = htons(31337);
	
	bind(sock, (struct sockaddr *)&sobj, sizeof(sobj));
	
	while (1)
	{
		slen = sizeof(cobj);
		rlen = recvfrom(sock, mesg, 1024 * sizeof(char), 0, (struct sockaddr *)&cobj, &slen);
		strp(mesg, rlen);
		
		char *hptr = strrchr(mesg, ' '); if (hptr == NULL) { continue; }
		*hptr = '\0'; ++hptr;
		char *tptr = strrchr(mesg, ' '); if (tptr == NULL) { continue; }
		*tptr = '\0'; ++tptr;
		
		char *mptr = strrchr(mesg, ' '); if (mptr == NULL) { continue; }
		*mptr = '\0'; ++mptr;
		char *iptr = mesg;
		
		fobj = fopen(args[3], "r");
		while (1)
		{
			bzero(pass, 2048 * sizeof(char));
			if (fgets(pass, 1024 * sizeof(char), fobj) == NULL) { break; }
			
			/* note: passwords can not repeat or contain quotes */
			
			if (strstr(pass, "Cleartext-Password") == NULL) { continue; }
			char *aptr = strchr(pass, '"'); if (aptr == NULL) { continue; }
			++aptr;
			char *bptr = strchr(aptr, '"'); if (bptr == NULL) { continue; }
			*bptr = '\0';
			
			y = find(last, 256, aptr);
			if (y < 0) { continue; }
			
			bzero(temp, 2048 * sizeof(char));
			snprintf(temp, 1024 * sizeof(char), "%s %s", iptr, mptr);
			secs = atoi(tptr);
			
			if (vrfy(temp, 2048, aptr, hptr, last[y].t, secs, last[y].l) == 0)
			{
				last[y].t = time(NULL); last[y].l = secs;
				safe(iptr); safe(mptr);
				
				if (uniq(last, 256, y, ipvf(iptr)) < 0)
				{
					if ((aadr <= last[y].a) && (last[y].a <= badr))
					{
						bzero(sarp, 2048 * sizeof(char));
						snprintf(sarp, 1024 * sizeof(char), "arp -d '%s'", iptr);
						printf("exec=[%s]\n", sarp);
						system(sarp);
						
						bzero(sarp, 2048 * sizeof(char));
						snprintf(sarp, 1024 * sizeof(char), "arp -s '%s' '%s'", iptr, mptr);
						printf("exec=[%s]\n", sarp);
						system(sarp);
						
						bzero(sarp, 2048 * sizeof(char));
						snprintf(sarp, 1024 * sizeof(char), "%s %s", iadr, madr);
						sign(sarp, 2048, secs + 1, aptr);
						
						sendto(sock, sarp, strlen(sarp) * sizeof(char), 0, (struct sockaddr *)&cobj, sizeof(cobj));
						printf("sent=[%s]\n", sarp);
					}
					
					else
					{
						printf("erro=[range: %ld <= %ld <= %ld]\n", aadr, last[y].a, badr);
					}
				}
				
				else
				{
					printf("erro=[uniq: %ld]\n", ipvf(iptr));
				}
			}
			
			else
			{
				temp[30] = '\0';
				//printf("erro=[vrfy: (%s...) (%s) (%ld) (%ld)]\n", temp, hptr, secs, last[y].l);
			}
		}
		fclose(fobj);
	}
}

void ahnd(int sig)
{
	printf("No mesg\n");
}

void clnt(char **args)
{
	int sock, bron = 1;
	unsigned long tips, secs;
	char pass[2048], mesg[2048], temp[2048], sarp[2048];
	socklen_t slen;
	struct sockaddr_in cobj;
	
	//char *brod = "255.255.255.255";
	//signal(SIGALRM, ahnd);
	
	struct sigaction sact = { .sa_handler = ahnd, .sa_flags = 0 };
	sigaction(SIGALRM, &sact, NULL);
	
	bzero(pass, 2048 * sizeof(char));
	fgets(pass, 1024, stdin);
	strp(pass, strlen(pass));
	
	while (1)
	{
		char *iadr = gnet(args[2], 'i'), *madr = gnet(args[2], 'm'), *badr = gnet(args[2], 'b');
		
		sock = socket(AF_INET, SOCK_DGRAM, 0);
		setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &bron, sizeof(bron));
		
		cobj.sin_family = AF_INET;
		cobj.sin_port = htons(31337);
		inet_aton(badr, (struct in_addr *)&cobj.sin_addr.s_addr);
		
		bzero(mesg, 2048 * sizeof(char));
		snprintf(mesg, 1024 * sizeof(char), "%s %s", iadr, madr);
		
		secs = time(NULL);
		sign(mesg, 2048, secs, pass);
		
		sendto(sock, mesg, strlen(mesg) * sizeof(char), 0, (struct sockaddr*)&cobj, sizeof(cobj));
		printf("Sent mesg %s with socket %d to %s\n", mesg, sock, badr);
		
		slen = sizeof(cobj);
		bzero(mesg, 2048 * sizeof(char));
		alarm(1);
		recvfrom(sock, mesg, 1024 * sizeof(char), 0, (struct sockaddr *)&cobj, &slen);
		alarm(0);
		strp(mesg, strlen(mesg));
		
		char *hptr = strrchr(mesg, ' '); if (hptr != NULL) { *hptr = '\0'; ++hptr; }
		char *tptr = strrchr(mesg, ' '); if (tptr != NULL) { *tptr = '\0'; ++tptr; }
		
		char *mptr = strrchr(mesg, ' ');
		char *iptr = mesg;
		
		if ((hptr != NULL) && (tptr != NULL) && (mptr != NULL))
		{
			bzero(temp, 2048 * sizeof(char));
			strcpy(temp, mesg);
			
			tips = atoi(tptr);
			*mptr = '\0'; ++mptr;
			
			if (vrfy(temp, 2048, pass, hptr, time(NULL) - 5, tips, secs) == 0)
			{
				safe(iptr); safe(mptr);
				
				bzero(sarp, 2048 * sizeof(char));
				snprintf(sarp, 1024 * sizeof(char), "arp -d '%s'", iptr);
				printf("exec=[%s]\n", sarp);
				system(sarp);
				
				bzero(sarp, 2048 * sizeof(char));
				snprintf(sarp, 1024 * sizeof(char), "arp -s '%s' '%s'", iptr, mptr);
				printf("exec=[%s]\n", sarp);
				system(sarp);
			}
			
			else
			{
				temp[30] = '\0';
				//printf("erro=[vrfy: (%s...) (%s) (%s) (%ld) (%ld)]\n", temp, pass, hptr, tips, secs);
			}
		}
		
		close(sock);
		//break;
		sleep(5);
	}
}

int main(int argc, char **argv)
{
	if (strcmp(argv[1], "s") == 0)
	{
		serv(argv);
	}
	
	if (strcmp(argv[1], "c") == 0)
	{
		clnt(argv);
	}
	
	return 0;
}

sha256.c

#define SHA256_LENGTH 32

#define uchar unsigned char // 8-bit byte
#define uint unsigned int // 32-bit word

// DBL_INT_ADD treats two unsigned ints a and b as one 64-bit integer and adds c to it
#define DBL_INT_ADD(a,b,c) if (a > 0xffffffff - (c)) ++b; a += c;
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b))))

#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))

typedef struct {
   uchar data[64];
   uint datalen;
   uint bitlen[2];
   uint state[8];
} SHA256_CTX;

uint k[64] = {
   0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
   0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
   0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
   0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
   0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
   0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
   0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
   0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};

void SHA256_TRANSFORM(SHA256_CTX *ctx, uchar data[])
{
   uint a,b,c,d,e,f,g,h,i,j,t1,t2,m[64];

   for (i=0,j=0; i < 16; ++i, j += 4)
      m[i] = (data[j] << 24) | (data[j+1] << 16) | (data[j+2] << 8) | (data[j+3]);
   for ( ; i < 64; ++i)
      m[i] = SIG1(m[i-2]) + m[i-7] + SIG0(m[i-15]) + m[i-16];

   a = ctx->state[0];
   b = ctx->state[1];
   c = ctx->state[2];
   d = ctx->state[3];
   e = ctx->state[4];
   f = ctx->state[5];
   g = ctx->state[6];
   h = ctx->state[7];

   for (i = 0; i < 64; ++i) {
      t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
      t2 = EP0(a) + MAJ(a,b,c);
      h = g;
      g = f;
      f = e;
      e = d + t1;
      d = c;
      c = b;
      b = a;
      a = t1 + t2;
   }

   ctx->state[0] += a;
   ctx->state[1] += b;
   ctx->state[2] += c;
   ctx->state[3] += d;
   ctx->state[4] += e;
   ctx->state[5] += f;
   ctx->state[6] += g;
   ctx->state[7] += h;
}

void SHA256_INIT(SHA256_CTX *ctx)
{
   ctx->datalen = 0;
   ctx->bitlen[0] = 0;
   ctx->bitlen[1] = 0;
   ctx->state[0] = 0x6a09e667;
   ctx->state[1] = 0xbb67ae85;
   ctx->state[2] = 0x3c6ef372;
   ctx->state[3] = 0xa54ff53a;
   ctx->state[4] = 0x510e527f;
   ctx->state[5] = 0x9b05688c;
   ctx->state[6] = 0x1f83d9ab;
   ctx->state[7] = 0x5be0cd19;
}

void SHA256_UPDATE(SHA256_CTX *ctx, uchar data[], uint len)
{
   uint i;

   for (i=0; i < len; ++i) {
      ctx->data[ctx->datalen] = data[i];
      ctx->datalen++;
      if (ctx->datalen == 64) {
         SHA256_TRANSFORM(ctx,ctx->data);
         DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],512);
         ctx->datalen = 0;
      }
   }
}

void SHA256_FINAL(SHA256_CTX *ctx, uchar hash[])
{
   uint i;

   i = ctx->datalen;

   // Pad whatever data is left in the buffer.
   if (ctx->datalen < 56) {
      ctx->data[i++] = 0x80;
      while (i < 56)
         ctx->data[i++] = 0x00;
   }
   else {
      ctx->data[i++] = 0x80;
      while (i < 64)
         ctx->data[i++] = 0x00;
      SHA256_TRANSFORM(ctx,ctx->data);
      memset(ctx->data,0,56);
   }

   // Append to the padding the total message's length in bits and transform.
   DBL_INT_ADD(ctx->bitlen[0],ctx->bitlen[1],ctx->datalen * 8);
   ctx->data[63] = ctx->bitlen[0];
   ctx->data[62] = ctx->bitlen[0] >> 8;
   ctx->data[61] = ctx->bitlen[0] >> 16;
   ctx->data[60] = ctx->bitlen[0] >> 24;
   ctx->data[59] = ctx->bitlen[1];
   ctx->data[58] = ctx->bitlen[1] >> 8;
   ctx->data[57] = ctx->bitlen[1] >> 16;
   ctx->data[56] = ctx->bitlen[1] >> 24;
   SHA256_TRANSFORM(ctx,ctx->data);

   // Since this implementation uses little endian byte ordering and SHA uses big endian,
   // reverse all the bytes when copying the final state to the output hash.
   for (i=0; i < 4; ++i) {
      hash[i]    = (ctx->state[0] >> (24-i*8)) & 0x000000ff;
      hash[i+4]  = (ctx->state[1] >> (24-i*8)) & 0x000000ff;
      hash[i+8]  = (ctx->state[2] >> (24-i*8)) & 0x000000ff;
      hash[i+12] = (ctx->state[3] >> (24-i*8)) & 0x000000ff;
      hash[i+16] = (ctx->state[4] >> (24-i*8)) & 0x000000ff;
      hash[i+20] = (ctx->state[5] >> (24-i*8)) & 0x000000ff;
      hash[i+24] = (ctx->state[6] >> (24-i*8)) & 0x000000ff;
      hash[i+28] = (ctx->state[7] >> (24-i*8)) & 0x000000ff;
   }
}

Leave a comment