mirror of
https://github.com/SerenityOS/serenity
synced 2026-04-25 17:15:42 +02:00
SSHServer: Add support for writing keylog files
These files are used by wireshark to decode SSH packets. This is really
useful for inspecting the traffic after the SSH peers started
encryption.
To use it, you need to pass --unsafe-keylog-file FILE when starting the
server and then make Wireshark's ssh.keylog_file setting point to the
same file.
Note that this option leaks secrets to the file system and thus is not
safe to use.
The file format is described here:
6add14a3f3/epan/dissectors/packet-ssh.c (L2684-2704)
This commit is contained in:
@@ -129,9 +129,9 @@ ErrorOr<void> SSHClient::send_key_protocol_message()
|
||||
|
||||
TRY(stream.write_value<u8>(to_underlying(MessageID::KEXINIT)));
|
||||
|
||||
auto cookie = TRY(ByteBuffer::create_uninitialized(16));
|
||||
fill_with_random(cookie);
|
||||
TRY(stream.write_until_depleted(cookie));
|
||||
m_cookie = TRY(ByteBuffer::create_uninitialized(16));
|
||||
fill_with_random(m_cookie);
|
||||
TRY(stream.write_until_depleted(m_cookie));
|
||||
|
||||
TRY(encode_name_list(stream, KEX_ALGORITHMS));
|
||||
TRY(encode_name_list(stream, SERVER_HOST_KEY_ALGORITHMS));
|
||||
@@ -199,6 +199,15 @@ ErrorOr<void> SSHClient::send_ecdh_reply(ByteBuffer&& client_public_key)
|
||||
// "Compute shared secret."
|
||||
auto shared_secret = TRY(curve.compute_coordinate(private_key, client_public_key));
|
||||
m_key_exchange_data.shared_secret = shared_secret;
|
||||
|
||||
if (auto keylog_file = ServerConfiguration::the().keylog_file(); keylog_file.has_value()) {
|
||||
auto file = TRY(Core::File::open(*keylog_file, Core::File::OpenMode::Write | Core::File::OpenMode::Append));
|
||||
TRY(file->write_until_depleted(ByteString::formatted("{:hex-dump}"sv, m_cookie.bytes())));
|
||||
TRY(file->write_until_depleted(" SHARED_SECRET "sv));
|
||||
TRY(file->write_until_depleted(ByteString::formatted("{:hex-dump}\n"sv, shared_secret.bytes())));
|
||||
}
|
||||
m_cookie = {};
|
||||
|
||||
set_shared_secret(move(shared_secret));
|
||||
|
||||
// FIXME: Abort if shared_point is not valid (at least when it's all zero, maybe there are other cases too).
|
||||
|
||||
@@ -100,6 +100,7 @@ private:
|
||||
Core::TCPSocket& m_tcp_socket;
|
||||
|
||||
KeyExchangeData m_key_exchange_data {};
|
||||
ByteBuffer m_cookie {};
|
||||
|
||||
Vector<Session> m_sessions;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,9 @@ public:
|
||||
m_user_authorized_keys_file = path;
|
||||
}
|
||||
|
||||
void set_keylog_file(StringView path) { m_keylog_file = path; }
|
||||
Optional<ByteString> keylog_file() const { return m_keylog_file; }
|
||||
|
||||
ErrorOr<Vector<TypedBlob>> get_authorized_keys_for_user() const;
|
||||
|
||||
private:
|
||||
@@ -43,6 +46,7 @@ private:
|
||||
bool m_use_unsafe_stubbed_private_key { false };
|
||||
|
||||
ByteString m_user_authorized_keys_file;
|
||||
Optional<ByteString> m_keylog_file;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -57,10 +57,12 @@ ErrorOr<int> serenity_main(Main::Arguments args)
|
||||
Optional<u32> port {};
|
||||
bool unsafe_stub_private_key { false };
|
||||
Optional<StringView> user_authorized_keys_file {};
|
||||
Optional<StringView> keylog_file {};
|
||||
|
||||
Core::ArgsParser parser;
|
||||
parser.add_option(port, "Port to listen on", "port", 'p', "port");
|
||||
parser.add_option(user_authorized_keys_file, "File to read the user's authorized keys from", "user-authorized-keys-file", 0, "FILE");
|
||||
parser.add_option(keylog_file, "File to log the connections keys to - UNSAFE", "unsafe-keylog-file", 0, "FILE");
|
||||
parser.add_option(unsafe_stub_private_key, "Stub the server's private key - UNSAFE", "unsafe-stub-private-key");
|
||||
|
||||
parser.parse(args);
|
||||
@@ -74,6 +76,9 @@ ErrorOr<int> serenity_main(Main::Arguments args)
|
||||
if (user_authorized_keys_file.has_value())
|
||||
SSH::Server::ServerConfiguration::the().set_user_authorized_keys_file(*user_authorized_keys_file);
|
||||
|
||||
if (keylog_file.has_value())
|
||||
SSH::Server::ServerConfiguration::the().set_keylog_file(*keylog_file);
|
||||
|
||||
Core::EventLoop loop;
|
||||
|
||||
g_tcp_server = TRY(Core::TCPServer::try_create());
|
||||
|
||||
Reference in New Issue
Block a user