From d2377735994b87f99f994ad0ef04b85845bb854d Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Tue, 8 Jan 2002 11:57:32 +0000 Subject: [PATCH] Add the CRC32 compensation attack detector that all other SSH clients have had for ages and I forgot about. Of course I've got the version with the buffer overflow fixed! [originally from svn r1535] --- LICENCE | 3 +- Makefile | 6 +- doc/licence.but | 5 +- pageant.rc | 2 +- puttygen.rc | 2 +- ssh.c | 5 ++ ssh.h | 4 ++ sshcrc.c | 8 ++- sshcrcda.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ win_res.rc | 2 +- 10 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 sshcrcda.c diff --git a/LICENCE b/LICENCE index 28cccffb..f1c94167 100644 --- a/LICENCE +++ b/LICENCE @@ -1,7 +1,8 @@ PuTTY is copyright 1997-2001 Simon Tatham. Portions copyright Robert de Bath, Joris van Rantwijk, Delian -Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry. +Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, +and CORE SDI S.A. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files diff --git a/Makefile b/Makefile index b69762a0..6ae9268b 100644 --- a/Makefile +++ b/Makefile @@ -115,9 +115,9 @@ MOBJ2 = tree234.$(OBJ) COBJS = console.$(OBJ) ##-- objects putty pscp psftp plink OBJS1 = sshcrc.$(OBJ) sshdes.$(OBJ) sshmd5.$(OBJ) sshrsa.$(OBJ) sshrand.$(OBJ) -OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshdss.$(OBJ) -OBJS3 = sshbn.$(OBJ) sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) sshzlib.$(OBJ) -OBJS4 = x11fwd.$(OBJ) portfwd.$(OBJ) sshaes.$(OBJ) sshsh512.$(OBJ) +OBJS2 = sshsha.$(OBJ) sshblowf.$(OBJ) noise.$(OBJ) sshdh.$(OBJ) sshcrcda.$(OBJ) +OBJS3 = sshpubk.$(OBJ) ssh.$(OBJ) pageantc.$(OBJ) sshzlib.$(OBJ) sshdss.$(OBJ) +OBJS4 = x11fwd.$(OBJ) portfwd.$(OBJ) sshaes.$(OBJ) sshsh512.$(OBJ) sshbn.$(OBJ) ##-- objects pageant PAGE1 = pageant.$(OBJ) sshrsa.$(OBJ) sshpubk.$(OBJ) sshdes.$(OBJ) sshbn.$(OBJ) PAGE2 = sshmd5.$(OBJ) version.$(OBJ) tree234.$(OBJ) misc.$(OBJ) sshaes.$(OBJ) diff --git a/doc/licence.but b/doc/licence.but index 28994f67..f47d5dc8 100644 --- a/doc/licence.but +++ b/doc/licence.but @@ -1,11 +1,12 @@ -\versionid $Id: licence.but,v 1.1 2001/12/16 14:56:02 simon Exp $ +\versionid $Id: licence.but,v 1.2 2002/01/08 11:57:32 simon Exp $ \A{licence} PuTTY Licence PuTTY is copyright 1997-2001 Simon Tatham. Portions copyright Robert de Bath, Joris van Rantwijk, Delian -Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry. +Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, +and CORE SDI S.A. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files diff --git a/pageant.rc b/pageant.rc index 299995a6..2847e20a 100644 --- a/pageant.rc +++ b/pageant.rc @@ -66,7 +66,7 @@ BEGIN LTEXT "Portions copyright Robert de Bath, Joris van Rantwijk, Delian", 1001, 10, 26, 206, 8 LTEXT "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas", 1002, 10, 34, 206, 8 - LTEXT "Barry.", 1003, 10, 42, 206, 8 + LTEXT "Barry, and CORE SDI S.A.", 1003, 10, 42, 206, 8 LTEXT "Permission is hereby granted, free of charge, to any person", 1004, 10, 58, 206, 8 LTEXT "obtaining a copy of this software and associated documentation", 1005, 10, 66, 206, 8 diff --git a/puttygen.rc b/puttygen.rc index b7711c3c..7d1ff22d 100644 --- a/puttygen.rc +++ b/puttygen.rc @@ -59,7 +59,7 @@ BEGIN LTEXT "Portions copyright Robert de Bath, Joris van Rantwijk, Delian", 1001, 10, 26, 206, 8 LTEXT "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas", 1002, 10, 34, 206, 8 - LTEXT "Barry.", 1003, 10, 42, 206, 8 + LTEXT "Barry, and CORE SDI S.A.", 1003, 10, 42, 206, 8 LTEXT "Permission is hereby granted, free of charge, to any person", 1004, 10, 58, 206, 8 LTEXT "obtaining a copy of this software and associated documentation", 1005, 10, 66, 206, 8 diff --git a/ssh.c b/ssh.c index 115c0ce6..b8abc5ba 100644 --- a/ssh.c +++ b/ssh.c @@ -724,6 +724,11 @@ static int ssh1_rdpkt(unsigned char **data, int *datalen) st->to_read -= st->chunk; } + if (cipher && detect_attack(pktin.data, st->biglen, NULL)) { + bombout(("Network attack (CRC compensation) detected!")); + crReturn(0); + } + if (cipher) cipher->decrypt(pktin.data, st->biglen); diff --git a/ssh.h b/ssh.h index 3981066c..7857f152 100644 --- a/ssh.h +++ b/ssh.h @@ -72,6 +72,10 @@ typedef unsigned int word32; typedef unsigned int uint32; unsigned long crc32(const void *s, size_t len); +unsigned long crc32_update(unsigned long crc_input, const void *s, size_t len); + +/* SSH CRC compensation attack detector */ +int detect_attack(unsigned char *buf, uint32 len, unsigned char *IV); typedef struct { uint32 h[4]; diff --git a/sshcrc.c b/sshcrc.c index fb0db0ca..691f7b4e 100644 --- a/sshcrc.c +++ b/sshcrc.c @@ -211,9 +211,8 @@ int main(void) } #endif -unsigned long crc32(const void *buf, size_t len) +unsigned long crc32_update(unsigned long crcword, const void *buf, size_t len) { - unsigned long crcword = 0L; const unsigned char *p = (const unsigned char *) buf; while (len--) { unsigned long newbyte = *p++; @@ -222,3 +221,8 @@ unsigned long crc32(const void *buf, size_t len) } return crcword; } + +unsigned long crc32(const void *buf, size_t len) +{ + return crc32_update(0L, buf, len); +} diff --git a/sshcrcda.c b/sshcrcda.c new file mode 100644 index 00000000..7b683be9 --- /dev/null +++ b/sshcrcda.c @@ -0,0 +1,157 @@ +/* $OpenBSD: deattack.c,v 1.14 2001/06/23 15:12:18 itojun Exp $ */ + +/* + * Cryptographic attack detector for ssh - source code + * + * Copyright (c) 1998 CORE SDI S.A., Buenos Aires, Argentina. + * + * All rights reserved. Redistribution and use in source and binary + * forms, with or without modification, are permitted provided that + * this copyright notice is retained. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR + * CONSEQUENTIAL DAMAGES RESULTING FROM THE USE OR MISUSE OF THIS + * SOFTWARE. + * + * Ariel Futoransky + * + * + * Modified for use in PuTTY by Simon Tatham + */ + +#include +#include "misc.h" +#include "ssh.h" + +typedef unsigned char uchar; +typedef unsigned short uint16; + +/* SSH Constants */ +#define SSH_MAXBLOCKS (32 * 1024) +#define SSH_BLOCKSIZE (8) + +/* Hashing constants */ +#define HASH_MINSIZE (8 * 1024) +#define HASH_ENTRYSIZE (sizeof(uint16)) +#define HASH_FACTOR(x) ((x)*3/2) +#define HASH_UNUSEDCHAR (0xff) +#define HASH_UNUSED (0xffff) +#define HASH_IV (0xfffe) + +#define HASH_MINBLOCKS (7*SSH_BLOCKSIZE) + +#define GET_32BIT_MSB_FIRST(cp) \ + (((unsigned long)(unsigned char)(cp)[0] << 24) | \ + ((unsigned long)(unsigned char)(cp)[1] << 16) | \ + ((unsigned long)(unsigned char)(cp)[2] << 8) | \ + ((unsigned long)(unsigned char)(cp)[3])) + +/* Hash function (Input keys are cipher results) */ +#define HASH(x) GET_32BIT_MSB_FIRST(x) + +#define CMP(a, b) (memcmp(a, b, SSH_BLOCKSIZE)) + +uchar ONE[4] = { 1, 0, 0, 0 }; +uchar ZERO[4] = { 0, 0, 0, 0 }; + +static void crc_update(uint32 *a, void *b) +{ + *a = crc32_update(*a, b, 4); +} + +/* detect if a block is used in a particular pattern */ +static int check_crc(uchar *S, uchar *buf, uint32 len, uchar *IV) +{ + uint32 crc; + uchar *c; + + crc = 0; + if (IV && !CMP(S, IV)) { + crc_update(&crc, ONE); + crc_update(&crc, ZERO); + } + for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { + if (!CMP(S, c)) { + crc_update(&crc, ONE); + crc_update(&crc, ZERO); + } else { + crc_update(&crc, ZERO); + crc_update(&crc, ZERO); + } + } + return (crc == 0); +} + +/* Detect a crc32 compensation attack on a packet */ +int detect_attack(uchar *buf, uint32 len, uchar *IV) +{ + static uint16 *h = (uint16 *) NULL; + static uint32 n = HASH_MINSIZE / HASH_ENTRYSIZE; + register uint32 i, j; + uint32 l; + register uchar *c; + uchar *d; + + assert(!(len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) || + len % SSH_BLOCKSIZE != 0)); + for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2) + ; + + if (h == NULL) { + logevent("Installing CRC compensation attack detector"); + n = l; + h = (uint16 *) smalloc(n * HASH_ENTRYSIZE); + } else { + if (l > n) { + n = l; + h = (uint16 *) srealloc(h, n * HASH_ENTRYSIZE); + } + } + + if (len <= HASH_MINBLOCKS) { + for (c = buf; c < buf + len; c += SSH_BLOCKSIZE) { + if (IV && (!CMP(c, IV))) { + if ((check_crc(c, buf, len, IV))) + return 1; /* attack detected */ + else + break; + } + for (d = buf; d < c; d += SSH_BLOCKSIZE) { + if (!CMP(c, d)) { + if ((check_crc(c, buf, len, IV))) + return 1; /* attack detected */ + else + break; + } + } + } + return 0; /* ok */ + } + memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE); + + if (IV) + h[HASH(IV) & (n - 1)] = HASH_IV; + + for (c = buf, j = 0; c < (buf + len); c += SSH_BLOCKSIZE, j++) { + for (i = HASH(c) & (n - 1); h[i] != HASH_UNUSED; + i = (i + 1) & (n - 1)) { + if (h[i] == HASH_IV) { + if (!CMP(c, IV)) { + if (check_crc(c, buf, len, IV)) + return 1; /* attack detected */ + else + break; + } + } else if (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) { + if (check_crc(c, buf, len, IV)) + return 1; /* attack detected */ + else + break; + } + } + h[i] = j; + } + return 0; /* ok */ +} diff --git a/win_res.rc b/win_res.rc index d2d81d19..c35bc8e2 100644 --- a/win_res.rc +++ b/win_res.rc @@ -87,7 +87,7 @@ BEGIN LTEXT "Portions copyright Robert de Bath, Joris van Rantwijk, Delian", 1001, 10, 26, 206, 8 LTEXT "Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas", 1002, 10, 34, 206, 8 - LTEXT "Barry.", 1003, 10, 42, 206, 8 + LTEXT "Barry, and CORE SDI S.A.", 1003, 10, 42, 206, 8 LTEXT "Permission is hereby granted, free of charge, to any person", 1004, 10, 58, 206, 8 LTEXT "obtaining a copy of this software and associated documentation", 1005, 10, 66, 206, 8