nmap / ncrack

Ncrack network authentication tool
Other
1.08k stars 237 forks source link

Fix segfault in the ssh plugin on Centos 8 #108

Closed schischi closed 3 years ago

schischi commented 3 years ago

On Centos 8 (7 as well?) ncrack segfaults when the SSH plugin is being used.

Build ncrack with the default flags for centos ($RPM_OPT_FLAGS):

$ CFLAGS='-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
$ CXXFLAGS=$CFLAGS
$ LDFLAGS='-Wl,-z,relro  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld'
$ export CFLAGS CXXFLAGS LDFLAGS
$ ./configure --build=x86_64-redhat-linux-gnu --host=x86_64-redhat-linux-gnu

$ ./ncrack --pairwise --user root --pass vagrant $HOSTNAME:22
zsh: segmentation fault (core dumped)

The following line is the source of the segfault (sshkey.c): key->cert->principals[key->cert->nprincipals++] = principal;

With gdb, we can see that the pointer returned by reallocarray() is invalid:

(gdb) p key->cert->principals
$1 = (char **) 0x5585dfb0
(gdb) x 0x5585dfb0
0x5585dfb0: Cannot access memory at address 0x5585dfb0
(gdb) x 0x55555585dfb0
0x55555585dfb0: 0x5585e230

As we can see the pointer is valid, but the address has been truncated: 32 bits instead of 64, and so we get a segfault.

The program has been compiled with HAVE_REALLOCARRAY=1, and the glibc version does support it (v.2.28), but we need to use __GNU_SOURCE to have the prototypes. If we look at includes.h, we include stdlib.h (where reallocarray is supposed to be defined) and THEN we set __GNU_SOURCE, so we end up with the prototype of reallocarray to NOT be included.

We end up with a warning during the compilation:

sshkey.c:1947:27: warning: implicit declaration of function ‘reallocarray’; did you mean ‘recallocarray’? [-Wimplicit-function-declaration]
key->cert->principals = reallocarray(key->cert->principals,

But because we don't have -Werror, the code is still compiled and the compiler assumes the function returns an integer... (32 bit). The linking phase is working just fine, and the function reallocarray is properly linked, but the code in ncrack assumes the return value is a 32bit integer instead of a 64bit pointer and we end up with a truncated address.

The fix is pretty trivial: we need to define __GNU_SOURCE BEFORE including stdlib.h The code used to work fine in the past because we had #include <malloc.h> (which contains the prototype of reallocarray), but it got removed by this commit 440751f515ffb7f88c308288 and we ended up with this missing prototype. Defining __GNU_SOURCE instead of including malloc.h is better because the latter is deprecated.

After applying this patch and compiling ncrack, we get:

$ ./ncrack --pairwise --user root --pass vagrant $HOSTNAME:22
Starting Ncrack 0.8 ( http://ncrack.org ) at 2021-05-10 09:30 PDT
Ncrack done: 1 service scanned in 3.00 seconds.
Ncrack finished.