Bugtraq mailing list archives

Sequence number spoofing, SunOS


From: mouse () Collatz McRCIM McGill EDU (der Mouse)
Date: Tue, 24 Jan 1995 14:54:30 -0500


Some of you may recall that I wrote something about hashing various
things into tcp_iss, things like network packets and inodes read from
disk.  Someone wrote to me privately and said

The basic problem is you want an absolute minimum cpu overhead per
packet, granted this isn't as important today as it was in the time
the sun3/50's were popular on the net.

My reaction to this is basically that I'd rather have a slower machine
that resists attacks than a fast one that gets broken wide open, but it
is a valid point.

Here's something I concocted for sun4c machines under SunOS 4.1.2; I
believe it should work for any 4.1.x system, possibly with minor
tweaks.  It treats tcp_iss as a CRC accumulator into which it hashes
every IP output packet.  This is perhaps not as strong as it might be,
but it's a hell of a lot better than what we used to have, and if the
machine is at all busy on the network the attacker faces essentially
random sequence numbers.  (Perhaps I should also call uniqtime and hash
that in too.)

It does cost some cpu cycles for each output packet, it's true.  Nobody
has to run it.

This is designed to be dropped into some two-level directory under
/sys.  I use /sys/local/OBJ; you can move it anywhere you like by
changing the path in the Makefile that fetches ip_output out of the OBJ
directory.  You will need to do this anyway if you're building for
other than sun4c kernel architecture.

                                        der Mouse

                            mouse () collatz mcrcim mcgill edu

Legalisms: As its sole author, I place all this code - including the
"patchsym" auxiliary program - into the public domain.  Anyone may use
it for any purpose...though I would appreciate credit where it's due.
I make no promises about its worth for any purpose; the decision and
the risk are all yours.  It's free, and you get what you pay for.

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Tue Jan 24 14:37:29 1995
# Run this through sh to create:
#       Makefile
#       patch.s
#       patchsym.c
#       crc.c
echo x - Makefile \(571 characters\)
sed 's/^X//' > Makefile << \EOF
XASFLAGS = -P
XCFLAGS = -O
X
Xip_output.o: ip_output-sympatch.o patch.o crc.o
X       ld -x -r -o ip_output.o ip_output-sympatch.o patch.o crc.o
X
Xip_output-sympatch.o: ip_output-dist.o patchsym
X       cp ip_output-dist.o _.o
X       ./patchsym _.o _ip_output _ip_output_wrapped
X       mv _.o ip_output-sympatch.o
X
Xip_output-dist.o: ../../sun4c/OBJ/ip_output.o
X       cp ../../sun4c/OBJ/ip_output.o ip_output-dist.o
X
Xpatch.o: patch.s
X       $(AS) $(ASFLAGS) patch.s -o patch.o
X
Xcrc.o: crc.c
X       $(CC) $(CFLAGS) -c crc.c
X
Xpatchsym: patchsym.c
X       $(CC) -o patchsym patchsym.c
X
Xclean:
X       @touch _.o
X       rm -f *.o patchsym core
EOF
if test 571 -ne "`wc -c Makefile`"
then
echo shar: error transmitting Makefile \(should have been 571 characters\)
fi
echo x - patch.s \(234 characters\)
sed 's/^X//' > patch.s << \EOF
X#include <sparc/asm_linkage.h>
X
X       .global _ip_output_wrapped
X       .global _ip_output
X       .global _corrupt_iss
X
X       .seg    "text"
X_ip_output:
X       save    %sp,-SA(MINFRAME),%sp
X       call    _corrupt_iss
X       mov     %i0,%o0
X       set     _ip_output_wrapped,%o0
X       jmp     %o0
X       restore
EOF
if test 234 -ne "`wc -c patch.s`"
then
echo shar: error transmitting patch.s \(should have been 234 characters\)
fi
echo x - patchsym.c \(3670 characters\)
sed 's/^X//' > patchsym.c << \EOF
X/*
X * patchsym a.out old new [old new [old new ... ]]
X *
X * Modifies the given a.out in-place to change symbol names as given on the
X *  command line.
X */
X
X#include <stdio.h>
X#include <a.out.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <unistd.h>
X#include <fcntl.h>
X
X/*extern*/ char **argvec;
X
Xcaddr_t sbrk();
X#define SBRKERR ((caddr_t)-1)
X
Xint aout_fd;
Xstruct stat stb;
Xstruct exec hdr;
Xint symsize;
Xchar *symtbl;
Xint strsize;
Xchar *strtbl;
X
Xgrowstrings(nb)
Xint nb;
X{
X char *new;
X
X new = sbrk(nb);
X if (new != strtbl+strsize)
X  { sbrk(strsize);
X    bcopy(strtbl,new,strsize);
X  }
X strsize += nb;
X}
X
Xmain(ac,av)
Xint ac;
Xchar **av;
X{
X int nchg;
X int i;
X int j;
X int l;
X struct nlist *sym;
X char *name;
X
X argvec = av;
X if ((ac & 1) || (ac < 4))
X  { fprintf(stderr,"Usage: %s a.out-file old new [old new [old new ... ]]\n",argvec[0]);
X    exit(1);
X  }
X nchg = (ac / 2) - 1;
X#define OLDNAME(i) av[(((i)*2)+2)]
X#define NEWNAME(i) av[(((i)*2)+3)]
X/*
X for (i=0;i<nchg;i++)
X  { if (strlen(OLDNAME(i)) != strlen(NEWNAME(i)))
X     { fprintf(stderr,"%s: old and new symbol names must be the same length 
(%s->%s)\n",argvec[0],OLDNAME(i),NEWNAME(i));
X       exit(1);
X     }
X  }
X*/
X aout_fd = open(av[1],O_RDWR,0);
X if (aout_fd < 0)
X  { fprintf(stderr,"%s: can't open ",argvec[0]);
X    perror(av[1]);
X    exit(1);
X  }
X if (fstat(aout_fd,&stb) < 0)
X  { fprintf(stderr,"%s: can't get size of %s\n",argvec[0],av[1]);
X    exit(1);
X  }
X if (read(aout_fd,(char *)&hdr,sizeof(hdr)) != sizeof(hdr))
X  { fprintf(stderr,"%s: can't read a.out header from %s\n",argvec[0],av[1]);
X    exit(1);
X  }
X if (N_BADMAG(hdr))
X  { fprintf(stderr,"%s: %s: bad magic number\n",argvec[0],av[1]);
X    exit(1);
X  }
X symsize = hdr.a_syms / sizeof(struct nlist);
X symtbl = sbrk(symsize*sizeof(struct nlist));
X if (symtbl == SBRKERR)
X  { fprintf(stderr,"%s: can't allocate %lu bytes of memory for symbol table\n",symsize*sizeof(struct nlist));
X    exit(1);
X  }
X strsize = stb.st_size - N_STROFF(hdr);
X strtbl = sbrk(strsize+1);
X if (strtbl == SBRKERR)
X  { fprintf(stderr,"%s: can't allocate %d bytes of memory for string table\n",strsize);
X    exit(1);
X  }
X if ( (lseek(aout_fd,N_SYMOFF(hdr),SEEK_SET) < 0) ||
X      (read(aout_fd,symtbl,hdr.a_syms) != hdr.a_syms) )
X  { fprintf(stderr,"%s: can't read symbol table from %s\n",argvec[0],av[1]);
X    exit(1);
X  }
X if ( (lseek(aout_fd,N_STROFF(hdr),SEEK_SET) < 0) ||
X      (read(aout_fd,strtbl,strsize) != strsize) )
X  { fprintf(stderr,"%s: can't read string table from %s\n",argvec[0],av[1]);
X    exit(1);
X  }
X if (strtbl[strsize-1] != '\0')
X  { growstrings(1);
X    strtbl[strsize-1] = '\0';
X  }
X for (i=0;i<symsize;i++)
X  { sym = ((struct nlist *) symtbl) + i;
X    if ((sym->n_un.n_strx <= 0) || (sym->n_un.n_strx >= strsize)) continue;
X    name = strtbl + sym->n_un.n_strx;
X    for (j=0;j<nchg;j++)
X     { if (!strcmp(name,OLDNAME(j))) break;
X     }
X    if (j < nchg)
X     { l = strlen(NEWNAME(j));
X       if (l <= strlen(OLDNAME(j)))
X       { strcpy(strtbl+sym->n_un.n_strx,NEWNAME(j));
X       }
X       else
X       { growstrings(l+1);
X         bcopy(NEWNAME(j),&strtbl[strsize-l-1],l+1);
X         sym->n_un.n_strx = strsize - l - 1;
X       }
X     }
X  }
X if ( (lseek(aout_fd,N_SYMOFF(hdr),SEEK_SET) < 0) ||
X      (write(aout_fd,(char *)symtbl,symsize*sizeof(struct nlist)) != symsize*sizeof(struct nlist)) )
X  { fprintf(stderr,"%s: error writing new symbol table, result is probably mangled\n",argvec[0]);
X    exit(1);
X  }
X *(int *)strtbl = strsize;
X if ( (lseek(aout_fd,N_STROFF(hdr),SEEK_SET) < 0) ||
X      (write(aout_fd,(char *)strtbl,strsize) != strsize) )
X  { fprintf(stderr,"%s: error writing new string table, result is probably mangled\n",argvec[0]);
X    exit(1);
X  }
X exit(0);
X}
EOF
if test 3670 -ne "`wc -c patchsym.c`"
then
echo shar: error transmitting patchsym.c \(should have been 3670 characters\)
fi
echo x - crc.c \(766 characters\)
sed 's/^X//' > crc.c << \EOF
X#include <sys/types.h>
X#include <sys/mbuf.h>
X
Xextern unsigned long int tcp_iss;
X
X#define POLY 0xedb88320
Xstatic unsigned long int crctable[256];
X
Xstatic void make_crctable()
X{
X register unsigned long int acc;
X register unsigned long int n;
X register int i;
X
X for (n=0;n<256;n++)
X  { acc = n;
X    for (i=0;i<8;i++)
X     { acc = (acc & 1) ? ((acc >> 1) ^ POLY) : (acc >> 1);
X     }
X    crctable[n] = acc;
X  }
X}
X
Xvoid corrupt_iss(m)
Xregister struct mbuf *m;
X{
X register unsigned long int acc;
X register unsigned char *dp;
X register int n;
X
X if (crctable[128] != POLY) make_crctable();
X acc = tcp_iss;
X for (;m;m=m->m_next)
X  { dp = mtod(m,unsigned char *);
X    for (n=m->m_len;n>0;n--)
X     { acc = (acc >> 8) ^ crctable[(acc&0xff)^*dp++];
X     }
X  }
X tcp_iss = acc;
X}
EOF
if test 766 -ne "`wc -c crc.c`"
then
echo shar: error transmitting crc.c \(should have been 766 characters\)
fi
exit 0
# end of shell archive



Current thread: