/* * NMAP Detection Module This module is an lkm for OpenBSD that detects OS * detection scans from Nmap. It is based heavily off of the wonderful LKM * tutorial from peter_a_werner@yahoo.com located at * http://undeadly.org/cgi?action=article&sid=20010812210650 * * To Compile: gcc -Wall -D_KERNEL -I/sys -c wafter.c * To Load: modload -o waftermod.o -ewafter wafter.o * * Warning! This has not been extensively tested. Do not run on a production * system, use at own risk. This is merely for my own amusement and was not * intended for real use. You have been warned! Feedback always welcomed. * Ober LinBSD ORG * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. 3. Neither the name * of the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * We will modify the entry for TCP in this structure. */ #define TH_BOG 0xc0 extern struct protosw inetsw[]; /* * Our prototypes */ extern int lkmexists __P((struct lkm_table *)); extern char *inet_ntoa __P((struct in_addr)); static void new_tcp_input __P((struct mbuf *,...)); static void new_icmp_input __P((struct mbuf *,...)); static void new_udp_input __P((struct mbuf *,...)); static void (*old_tcp_input) __P((struct mbuf *,...)); static void (*old_udp_input) __P((struct mbuf *,...)); static void (*old_icmp_input) __P((struct mbuf *,...)); /* * Declare and initialise our module structure */ MOD_MISC("waftermod") /* * Our handler function, used for load and unload. */ int wafter_handler(lkmtp, cmd) struct lkm_table *lkmtp; int cmd; { int s; switch (cmd) { case LKM_E_LOAD: /* * Provide some sanity checking, making sure the module * will not be loaded more than once. */ if (lkmexists(lkmtp)) return (EEXIST); /* * Block network protocol processing while we modify * the structure. We are changing the pointer to the * function tcp_input to our own wrapper function. */ s = splnet(); old_icmp_input = inetsw[4].pr_input; old_tcp_input = inetsw[2].pr_input; old_udp_input = inetsw[1].pr_input; inetsw[4].pr_input = new_icmp_input; inetsw[2].pr_input = new_tcp_input; inetsw[1].pr_input = new_udp_input; splx(s); break; case LKM_E_UNLOAD: /* * Restore the structure back to normal when we * are unloaded. */ s = splnet(); inetsw[1].pr_input = old_udp_input; inetsw[2].pr_input = old_tcp_input; inetsw[4].pr_input = old_icmp_input; splx(s); break; } return (0); } /* * Our external entry point, nothing to do but use DISPATCH. */ int wafter(lkmtp, cmd, ver) struct lkm_table *lkmtp; int cmd; int ver; { DISPATCH(lkmtp, cmd, ver, wafter_handler, wafter_handler, lkm_nofunc) } /* * Our tcp_input wrapper. If the mbuf represents a packet header, print * out the total length of the packet, the interface it was received on * and its source address. Then continue on with the original tcp_input. */ static void new_tcp_input(struct mbuf * m,...) { va_list ap; int iphlen; struct ifnet *ifnp; struct ip *ip; struct tcphdr *th; unsigned int destport = 0; unsigned int srcport = 0; va_start(ap, m); iphlen = va_arg(ap, int); va_end(ap); if (m->m_flags & M_PKTHDR) { ifnp = m->m_pkthdr.rcvif; ip = mtod(m, struct ip *); th = (struct tcphdr *) (ip + 1); srcport = ntohs(th->th_sport); destport = ntohs(th->th_dport); if ((th->th_flags & TH_FIN) && ((ip->ip_len == 10240) || (ip->ip_len == 20480) || (ip->ip_len == 40960))) { printf("NMAP FIN Scan from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } if ((th->th_flags & TH_FIN) && ((ip->ip_len != 10240) && (ip->ip_len != 20480) && (ip->ip_len != 40960))) { printf("Normal FIN from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } if ((th->th_flags & TH_SYN) && (th->th_flags & TH_ECE)) { printf("NMAP OS Detection Scan t1 from:%s on %s Flags:SYN|ECE", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_len); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } if (!th->th_flags) { printf("NMAP OS t2/Null Scan t2 from:%s on %s Flags:NULL", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } if ((th->th_flags & TH_FIN) && (th->th_flags & TH_SYN) && (th->th_flags & TH_PUSH) && (th->th_flags & TH_URG)) { printf("NMAP OS Detection Scan t3 from:%s on %s Flags:FIN|SYN|PUSH|URG", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } if ((th->th_flags & TH_FIN) && (th->th_flags & TH_PUSH) && (th->th_flags & TH_URG)) { printf("NMAP OS t4/XMAS Scan from:%s on %s Flags:FIN|PUSH|URG", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); th->th_flags = 0; } if ((th->th_flags == TH_SYN) && (ip->ip_len == 10240)) { printf("NMAP SYN Scan from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); th->th_flags = 0; } if ((th->th_flags == TH_SYN) && (ip->ip_len != 10240)) { printf("Other SYN connect from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } if ((th->th_flags == TH_SYN) && (ip->ip_len == 16384) && (th->th_win == 64)) { printf("NMAP -sT scan connect from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); th->th_flags = 0; } if ((th->th_flags & TH_RST) && (ip->ip_len == 10240)) { printf("TCPKILL RST from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); th->th_flags = 0; } if ((th->th_flags & TH_RST) && (ip->ip_len != 10240)) { printf("Other RST from:%s on %s", inet_ntoa(ip->ip_src), ifnp->if_xname); printf(" Details: srcport:%u dstport:%u seq:%d ack:%d x2:%d off:%d win:%d sum:%d urp:%d ipoff:%d size:%d\n", srcport, destport, th->th_seq, th->th_ack, th->th_x2, th->th_off, th->th_win, th->th_sum, th->th_urp, ip->ip_off, ip->ip_len); } } (*old_tcp_input) (m, iphlen); return; } static void new_icmp_input(struct mbuf * m,...) { struct icmp *icp; struct ip *ip = mtod(m, struct ip *); int icmplen; // void *(*ctlfunc)(int, struct sockaddr *, void *); int code, iphlen; va_list ap; //char buf[4 * sizeof("123")]; va_start(ap, m); iphlen = va_arg(ap, int); va_end(ap); //strlcpy(buf, inet_ntoa(ip->ip_dst), sizeof buf); printf("icmp from %s to %s, len %d\n", inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst), ntohs(ip->ip_len)); (*old_icmp_input) (m, iphlen); return; } static void new_udp_input(struct mbuf * m,...) { struct ip *ip; struct udphdr *uh; struct mbuf *opts = 0; struct ip save_ip; int iphlen, len, version; va_list ap; u_int16_t savesum; long unsigned srcport, destport; union { struct sockaddr sa; struct sockaddr_in sin; } srcsa, dstsa; va_start(ap, m); iphlen = va_arg(ap, int); va_end(ap); if (mtod(m, struct ip *)->ip_v == 4){ ip = mtod(m, struct ip *); srcsa.sa.sa_family = AF_INET; IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); if (uh){ srcport = ntohs(uh->uh_sport); destport = ntohs(uh->uh_dport); printf("UDP from:%s ", inet_ntoa(ip->ip_src)); printf(" Details: srcport:%u dstport:%u ulen:%d usum:%d size:%d\n", srcport, destport, uh->uh_ulen, uh->uh_sum, ip->ip_len); } } (*old_udp_input) (m, iphlen); return; }