From 170a96eb94e5a2d1f50cc3fd36c566353fddfaed Mon Sep 17 00:00:00 2001 From: Justin Crawford Date: Thu, 10 Oct 2019 19:48:32 -0700 Subject: [PATCH] Update mkpasswd to be slightly more secure Try to ensure that the mkpasswd command run in ssh sessions only echos to ssh client running that command. This gives us slightly more security against other session users seeing the hashed password. Fixed console sending with some of the APIs Updated version to 1.3.7 to match for next spigot + bungeecord release. --- README.md | 18 +-- pom.xml | 5 +- .../ryanmichela/sshd/ConsoleLogFormatter.java | 2 +- .../ryanmichela/sshd/ConsoleShellFactory.java | 14 ++- .../com/ryanmichela/sshd/MkpasswdCommand.java | 119 +++++++++--------- .../implementations/SSHDCommandSender.java | 23 +++- src/main/resources/plugin.yml | 2 +- 7 files changed, 100 insertions(+), 83 deletions(-) diff --git a/README.md b/README.md index 2730233..2a3a85b 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -Spigot-SSHD +Minecraft-SSHD =========== -[![Build Status](https://travis-ci.org/Justasic/Spigot-SSHD.svg?branch=master)](https://travis-ci.org/Justasic/Spigot-SSHD) -[![Release](https://img.shields.io/github/release/Justasic/Spigot-SSHD.svg?label=Release&maxAge=60)](https://github.com/Justasic/Spigot-SSHD/releases/latest) -[![GitHub license](https://img.shields.io/github/license/Justasic/Spigot-SSHD)](https://github.com/Justasic/Spigot-SSHD/blob/master/LICENSE) +[![Build Status](https://travis-ci.org/Justasic/Minecraft-SSHD.svg?branch=master)](https://travis-ci.org/Justasic/Minecraft-SSHD) +[![Release](https://img.shields.io/github/release/Justasic/Minecraft-SSHD.svg?label=Release&maxAge=60)](https://github.com/Justasic/Minecraft-SSHD/releases/latest) +[![GitHub license](https://img.shields.io/github/license/Justasic/Minecraft-SSHD)](https://github.com/Justasic/Minecraft-SSHD/blob/master/LICENSE) diskover
-**Have you ever wished you could remotely access your server's admin console without having to setup a complex remote access system? Now you can with SSHD.** +**Have you ever wished you could remotely access your server's admin console without having to setup a complex remote access system? Now you can with Minecraft-SSHD!** -SSHD securely exposes your BungeeCord admin console and the server filesystem using the SSH protocol - the same protocol that serves as the secure foundation for nearly all remote server administration.
+Minecraft-SSHD securely exposes your BungeeCord admin console and the server filesystem using the SSH protocol - the same protocol that serves as the secure foundation for nearly all remote server administration.
- Compatible with all ssh clients, regardless of operating system. - Remotely view your server log in real-time. @@ -20,7 +20,7 @@ SSHD securely exposes your BungeeCord admin console and the server filesystem us - Run Spigot without using screen or tmux (by adding `-noconsole`) - Remotely script your server by issuing one-off console commands with ssh. -### Why should I use SSHD? +### Why should I use Minecraft-SSHD? - You are in a shared hosting environment that only gives you access to the - log files. - You want to share access to your server console, but don't want to give anybody access to the machine its running on. @@ -93,8 +93,8 @@ mkpasswd supports the following hash algorithms: `sshd.mkpasswd` - Checks if the in-game user has access to run the mkpasswd command. -SSHD uses cryptographic certificates or a secure username and password to verify remote access. +Minecraft-SSHD uses cryptographic certificates or a secure username and password to verify remote access. ## Source Code -[Get the source on GitHub](https://github.com/Justasic/Spigot-SSHD "Source Code") +[Get the source on GitHub](https://github.com/Justasic/Minecraft-SSHD "Source Code") diff --git a/pom.xml b/pom.xml index 76fc8e8..edca522 100644 --- a/pom.xml +++ b/pom.xml @@ -6,8 +6,9 @@ com.ryanmichela sshd - 1.3.6.1 - https://github.com/Justasic/Bukkit-SSHD/ + Minecraft-SSHD: The SSH daemon for Minecraft servers. + 1.3.7 + https://github.com/Justasic/Minecraft-SSHD/ 1.8 diff --git a/src/main/java/com/ryanmichela/sshd/ConsoleLogFormatter.java b/src/main/java/com/ryanmichela/sshd/ConsoleLogFormatter.java index 629afce..f54d43d 100644 --- a/src/main/java/com/ryanmichela/sshd/ConsoleLogFormatter.java +++ b/src/main/java/com/ryanmichela/sshd/ConsoleLogFormatter.java @@ -96,7 +96,7 @@ public class ConsoleLogFormatter extends Formatter { stringbuilder.append(stringwriter.toString()); } - return stringbuilder.toString(); + return stringbuilder.toString().replace("\n", "\r\n"); } private void colorize(LogRecord logrecord) diff --git a/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java b/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java index d967e39..09d29b6 100644 --- a/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java +++ b/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java @@ -136,6 +136,8 @@ public class ConsoleShellFactory implements ShellFactory { if (command.equals("cls")) { this.ConsoleReader.clearScreen(); + this.ConsoleReader.drawLine(); + this.ConsoleReader.flush(); continue; } // Hide the mkpasswd command input from other users. @@ -152,10 +154,18 @@ public class ConsoleShellFactory implements ShellFactory { } else { + // Don't send our mkpasswd command output. This will echo passwords back + // to the console for all to see. This command is strictly between + // our plugin and the connected client. if (!mkpasswd) + { SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command); - - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); + } + else + { + Bukkit.dispatchCommand(this.SshdCommandSender, command); + } } }); } diff --git a/src/main/java/com/ryanmichela/sshd/MkpasswdCommand.java b/src/main/java/com/ryanmichela/sshd/MkpasswdCommand.java index 60cdc66..f4d3408 100644 --- a/src/main/java/com/ryanmichela/sshd/MkpasswdCommand.java +++ b/src/main/java/com/ryanmichela/sshd/MkpasswdCommand.java @@ -12,9 +12,28 @@ import com.ryanmichela.sshd.SshdPlugin; class MkpasswdCommand implements CommandExecutor { - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) + // Because Spigot's failed syntax API is really less than ideal (you should be required to add a + // SendSyntax function override), we're just always going to return true even for syntax failures + // as we will handle the syntax message internally. This also lets us send the messages more + // securely to the client without people knowing we're using the command. This prevents password + // or hash leakages from the user to other connected users. Plus this syntax will show how + // to both use the command and what hashes we support which is important for people who don't + // know how to RTFM. - Justin + private void SendSyntax(CommandSender sender, boolean invalid) { + if (invalid) + sender.sendMessage("\u00A7cInvalid Syntax\u00A7r"); + sender.sendMessage("\u00A7a/mkpasswd \u00A7r"); + sender.sendMessage("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r"); + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) + { + // If we're not mkpasswd, just fuck off. + if (!label.equalsIgnoreCase("mkpasswd")) + return false; + String algoritm, password; try { @@ -22,78 +41,52 @@ class MkpasswdCommand implements CommandExecutor // spaces in their passwords otherwise it won't be as strong as it should be. algoritm = args[0]; password = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); + if (password.trim().isEmpty()) // Shortcut to the catch statement below. + throw new ArrayIndexOutOfBoundsException(); } catch (ArrayIndexOutOfBoundsException e) { // ignore it. - return false; + this.SendSyntax(sender, true); + return true; } - // If they're console, allow regardless. - if (!(sender instanceof Player)) - { - if (label.equalsIgnoreCase("mkpasswd")) + boolean hasperm = (sender instanceof Player) ? ((Player)sender).hasPermission("sshd.mkpasswd") : true; + + if (hasperm) + { + try { - try + String hash = ""; + // Dumb but whatever. Some people are really dense. + if (algoritm.equalsIgnoreCase("PLAIN")) { - // Dumb but whatever. Some people are really dense. - if (algoritm.equalsIgnoreCase("PLAIN")) - { - // I mean c'mon... - sender.sendMessage("Bro really? it's literally your unencrypted password..."); - } - else if (algoritm.equalsIgnoreCase("pbkdf2")) - sender.sendMessage("Your hash: " + Cryptography.PBKDF2_HashPassword(password)); - else if (algoritm.equalsIgnoreCase("bcrypt")) - sender.sendMessage("Your hash: " + Cryptography.BCrypt_HashPassword(password)); - else if (algoritm.equalsIgnoreCase("sha256")) - sender.sendMessage("Your hash: " + Cryptography.SHA256_HashPassword(password)); - else if (algoritm.equalsIgnoreCase("help")) - sender.sendMessage("Supported hash algorithms: pbkdf2, bcrypt, sha256, plain"); - else - return false; + // I mean c'mon... + sender.sendMessage("Bro really? it's literally your unencrypted password..."); + return true; } - catch (Exception e) + else if (algoritm.equalsIgnoreCase("pbkdf2")) + hash = Cryptography.PBKDF2_HashPassword(password); + else if (algoritm.equalsIgnoreCase("bcrypt")) + hash = Cryptography.BCrypt_HashPassword(password); + else if (algoritm.equalsIgnoreCase("sha256")) + hash = Cryptography.SHA256_HashPassword(password); + else { - // We're console, just print the stack trace. - e.printStackTrace(); - return false; + this.SendSyntax(sender, !algoritm.equalsIgnoreCase("help")); + return true; } - return true; + + sender.sendMessage("\u00A79Your Hash: " + hash + "\u00A7r"); + } + catch (Exception e) + { + // We're console, just print the stack trace. + e.printStackTrace(); + sender.sendMessage("\u00A7cAn error occured. Please check console for details.\u00A7r"); } } - else - { - Player player = (Player) sender; - if (label.equalsIgnoreCase("mkpasswd")) - { - try - { - if (player.hasPermission("sshd.mkpasswd")) - { - // Dumb but whatever. Some people are really dense. - if (algoritm.equalsIgnoreCase("PLAIN")) - sender.sendMessage(password); - else if (algoritm.equalsIgnoreCase("pbkdf2")) - sender.sendMessage(Cryptography.PBKDF2_HashPassword(password)); - else if (algoritm.equalsIgnoreCase("bcrypt")) - sender.sendMessage(Cryptography.BCrypt_HashPassword(password)); - else if (algoritm.equalsIgnoreCase("sha256")) - sender.sendMessage(Cryptography.SHA256_HashPassword(password)); - else - return false; - } - } - catch (Exception e) - { - // since this is a player, send a failure message - sender.sendMessage("An error occured, please check console."); - e.printStackTrace(); - return false; - } - return true; - } - } - return false; - } + + return true; + } } \ No newline at end of file diff --git a/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java b/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java index 30b7baf..19a7cdf 100644 --- a/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java +++ b/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java @@ -16,21 +16,23 @@ import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.Plugin; import com.ryanmichela.sshd.ConsoleShellFactory; +import com.ryanmichela.sshd.ConsoleLogFormatter; import java.io.IOException; import java.util.Arrays; import java.util.Set; import java.util.logging.Level; -public class SSHDCommandSender implements ConsoleCommandSender, CommandSender { - +public class SSHDCommandSender implements ConsoleCommandSender, CommandSender +{ private final PermissibleBase perm = new PermissibleBase(this); private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker(); // Set by the upstream allocating function public ConsoleShellFactory.ConsoleShell console; - public void sendMessage(String message) { - this.sendRawMessage(message); + public void sendMessage(String message) + { + this.sendRawMessage(message + "\r"); } public void sendRawMessage(String message) @@ -40,7 +42,18 @@ public class SSHDCommandSender implements ConsoleCommandSender, CommandSender { return; try { - this.console.ConsoleReader.println(ChatColor.stripColor(message)); + this.console.ConsoleReader.println(ConsoleLogFormatter.ColorizeString(message).replace("\n", "\n\r")); + this.console.ConsoleReader.print(this.console.ConsoleReader.RESET_LINE + ""); + this.console.ConsoleReader.flush(); + try + { + this.console.ConsoleReader.drawLine(); + } + catch (Throwable ex) + { + this.console.ConsoleReader.getCursorBuffer().clear(); + } + this.console.ConsoleReader.flush(); } catch (IOException e) { diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index caf20ef..fb34c2c 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: SSHD version: ${project.version} -author: Ryan Michela, Haarolean, toxuin, Justin Crawford +author: Ryan Michela, Haarolean, toxuin, Justin Crawford, Zachery Coleman main: com.ryanmichela.sshd.SshdPlugin load: STARTUP commands: