mirror of
https://github.com/openssh/libopenssh
synced 2026-04-16 09:45:53 +00:00
Include CRC compensation attack detector in per-transport state structure
This commit is contained in:
committed by
Markus Friedl
parent
fbbec84071
commit
2a99b71b39
@@ -93,13 +93,17 @@ check_crc(u_char *S, u_char *buf, u_int32_t len)
|
||||
return crc == 0;
|
||||
}
|
||||
|
||||
void
|
||||
deattack_init(struct deattack_ctx *dctx)
|
||||
{
|
||||
bzero(dctx, sizeof(*dctx));
|
||||
dctx->n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
}
|
||||
|
||||
/* Detect a crc32 compensation attack on a packet */
|
||||
int
|
||||
detect_attack(u_char *buf, u_int32_t len)
|
||||
detect_attack(struct deattack_ctx *dctx, u_char *buf, u_int32_t len)
|
||||
{
|
||||
static u_int16_t *h = NULL;
|
||||
static u_int32_t n = HASH_MINSIZE / HASH_ENTRYSIZE;
|
||||
u_int16_t *tmp;
|
||||
u_int32_t i, j, l, same;
|
||||
u_char *c, *d;
|
||||
@@ -107,21 +111,23 @@ detect_attack(u_char *buf, u_int32_t len)
|
||||
if (len > (SSH_MAXBLOCKS * SSH_BLOCKSIZE) ||
|
||||
len % SSH_BLOCKSIZE != 0)
|
||||
return DEATTACK_ERROR;
|
||||
for (l = n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
for (l = dctx->n; l < HASH_FACTOR(len / SSH_BLOCKSIZE); l = l << 2)
|
||||
;
|
||||
|
||||
if (h == NULL) {
|
||||
if ((h = calloc(l, HASH_ENTRYSIZE)) == NULL)
|
||||
if (dctx->h == NULL) {
|
||||
if ((dctx->h = calloc(l, HASH_ENTRYSIZE)) == NULL)
|
||||
return DEATTACK_ERROR;
|
||||
n = l;
|
||||
dctx->n = l;
|
||||
} else {
|
||||
if (l > n) {
|
||||
if ((tmp = reallocn(h, l, HASH_ENTRYSIZE)) == NULL) {
|
||||
free(h);
|
||||
if (l > dctx->n) {
|
||||
if ((tmp = reallocn(dctx->h, l,
|
||||
HASH_ENTRYSIZE)) == NULL) {
|
||||
free(dctx->h);
|
||||
dctx->h = NULL;
|
||||
return DEATTACK_ERROR;
|
||||
}
|
||||
h = tmp;
|
||||
n = l;
|
||||
dctx->h = tmp;
|
||||
dctx->n = l;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,12 +144,12 @@ detect_attack(u_char *buf, u_int32_t len)
|
||||
}
|
||||
return DEATTACK_OK;
|
||||
}
|
||||
memset(h, HASH_UNUSEDCHAR, n * HASH_ENTRYSIZE);
|
||||
memset(dctx->h, HASH_UNUSEDCHAR, dctx->n * HASH_ENTRYSIZE);
|
||||
|
||||
for (c = buf, same = 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 (!CMP(c, buf + h[i] * SSH_BLOCKSIZE)) {
|
||||
for (i = HASH(c) & (dctx->n - 1); dctx->h[i] != HASH_UNUSED;
|
||||
i = (i + 1) & (dctx->n - 1)) {
|
||||
if (!CMP(c, buf + dctx->h[i] * SSH_BLOCKSIZE)) {
|
||||
if (++same > MAX_IDENTICAL)
|
||||
return DEATTACK_DOS_DETECTED;
|
||||
if (check_crc(c, buf, len))
|
||||
@@ -152,7 +158,7 @@ detect_attack(u_char *buf, u_int32_t len)
|
||||
break;
|
||||
}
|
||||
}
|
||||
h[i] = j;
|
||||
dctx->h[i] = j;
|
||||
}
|
||||
return DEATTACK_OK;
|
||||
}
|
||||
|
||||
@@ -28,5 +28,11 @@
|
||||
#define DEATTACK_DOS_DETECTED 2
|
||||
#define DEATTACK_ERROR 3
|
||||
|
||||
int detect_attack(u_char *, u_int32_t);
|
||||
struct deattack_ctx {
|
||||
u_int16_t *h;
|
||||
u_int32_t n;
|
||||
};
|
||||
|
||||
void deattack_init(struct deattack_ctx *);
|
||||
int detect_attack(struct deattack_ctx *, u_char *, u_int32_t);
|
||||
#endif
|
||||
|
||||
12
ssh/packet.c
12
ssh/packet.c
@@ -198,6 +198,9 @@ struct session_state {
|
||||
/* One-off warning about weak ciphers */
|
||||
int cipher_warning_done;
|
||||
|
||||
/* SSH1 CRC compensation attack detector */
|
||||
struct deattack_ctx deattack;
|
||||
|
||||
TAILQ_HEAD(, packet) outgoing;
|
||||
};
|
||||
|
||||
@@ -279,7 +282,7 @@ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out)
|
||||
(const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0)
|
||||
fatal("%s: cipher_init failed: %s", __func__, ssh_err(r));
|
||||
state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL;
|
||||
|
||||
deattack_init(&state->deattack);
|
||||
return ssh;
|
||||
}
|
||||
|
||||
@@ -1486,8 +1489,8 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
|
||||
* Ariel Futoransky(futo@core-sdi.com)
|
||||
*/
|
||||
if (!state->receive_context.plaintext) {
|
||||
switch (detect_attack(sshbuf_ptr(state->input),
|
||||
padded_len)) {
|
||||
switch (detect_attack(&state->deattack,
|
||||
sshbuf_ptr(state->input), padded_len)) {
|
||||
case DEATTACK_OK:
|
||||
break;
|
||||
case DEATTACK_DETECTED:
|
||||
@@ -1498,8 +1501,7 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
|
||||
ssh_packet_disconnect(ssh,
|
||||
"deattack denial of service detected");
|
||||
default:
|
||||
ssh_packet_disconnect(ssh,
|
||||
"deattack error");
|
||||
ssh_packet_disconnect(ssh, "deattack error");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user