diff --git a/conf/replies.properties b/conf/replies.properties new file mode 100644 index 0000000..677cdfd --- /dev/null +++ b/conf/replies.properties @@ -0,0 +1,7 @@ +hello=hello +5BAABD7C4581F90088133C0E945302C2=\t0\t0\t0 - +uname=Linux +9DD46246144D353C914D7572AEDF8EA6=Linux mail.vidconnect.cyou 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:10 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux +whoami=appadmin +4DE8A3B5E72E54D9D2A70BD43CB5EA9E=Model:\t\t0 +99EFF9F4022855955653078ECB2B4CE4=1.9G diff --git a/conf/springboot.yml b/conf/springboot.yml index a4628de..2f8d567 100644 --- a/conf/springboot.yml +++ b/conf/springboot.yml @@ -2,3 +2,5 @@ ssh-server: port: 1022 private-key: location: "conf/private.key" + automatic-replies: + location: "conf/replies.properties" diff --git a/pom.xml b/pom.xml index 94c531f..f91ee9d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.example.sshd echo-sshd-server - 1.0.1 + 1.0.2 ECHO SSH SERVER Learning Apache Mina SSHD library @@ -33,6 +33,10 @@ org.springframework.boot spring-boot-starter-log4j2 + + commons-codec + commons-codec + org.apache.mina mina-core diff --git a/src/main/java/com/example/sshd/config/OnetimeCommand.java b/src/main/java/com/example/sshd/config/OnetimeCommand.java new file mode 100644 index 0000000..9b90f91 --- /dev/null +++ b/src/main/java/com/example/sshd/config/OnetimeCommand.java @@ -0,0 +1,110 @@ +package com.example.sshd.config; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Properties; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.sshd.server.Command; +import org.apache.sshd.server.Environment; +import org.apache.sshd.server.ExitCallback; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Component +@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) +public class OnetimeCommand implements Command { + + private static final Logger logger = LoggerFactory.getLogger(OnetimeCommand.class); + + @Autowired + Properties repliesProperties; + + private InputStream in; + private OutputStream out; + private OutputStream err; + private ExitCallback callback; + private Environment environment; + private String command; + + public OnetimeCommand(String cmd) { + command = cmd; + } + + public InputStream getIn() { + return in; + } + + public OutputStream getOut() { + return out; + } + + public OutputStream getErr() { + return err; + } + + public Environment getEnvironment() { + return environment; + } + + @Override + public void setInputStream(InputStream in) { + this.in = in; + } + + @Override + public void setOutputStream(OutputStream out) { + this.out = out; + } + + @Override + public void setErrorStream(OutputStream err) { + this.err = err; + } + + @Override + public void setExitCallback(ExitCallback callback) { + this.callback = callback; + } + + @Override + public void start(Environment env) throws IOException { + environment = env; + String cmdHash = DigestUtils.md5Hex(command).toUpperCase(); + logger.info("command = {}, cmdHash = {}", command, cmdHash); + + if (StringUtils.equals(command, "exit")) { + logger.info("Exiting command detected: {}", command); + out.write(("\r\nExiting...\r\n").getBytes()); + } else if (repliesProperties.containsKey(command)) { + logger.info("Known command detected: {}", command); + String reply = repliesProperties.getProperty(command).replace("\\r", "\r").replace("\\n", "\n") + .replace("\\t", "\t"); + out.write(("\r\n" + reply + "\r\n").getBytes()); + } else if (repliesProperties.containsKey(cmdHash)) { + logger.info("Known command-hash detected: {}", cmdHash); + String reply = repliesProperties.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n") + .replace("\\t", "\t"); + out.write(("\r\n" + reply + "\r\n").getBytes()); + } else { + logger.info("Command not found: {}", command); + out.write(("\r\nCommand '" + command + "' not found. Try 'exit'.\r\n").getBytes()); + } + out.flush(); + callback.onExit(0); + } + + @Override + public void destroy() { + } + + public ExitCallback getCallback() { + return callback; + } +} diff --git a/src/main/java/com/example/sshd/config/SshConfig.java b/src/main/java/com/example/sshd/config/SshConfig.java index be51a98..d74052c 100644 --- a/src/main/java/com/example/sshd/config/SshConfig.java +++ b/src/main/java/com/example/sshd/config/SshConfig.java @@ -1,8 +1,10 @@ package com.example.sshd.config; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.security.NoSuchAlgorithmException; +import java.util.Properties; import org.apache.commons.lang3.StringUtils; import org.apache.sshd.SshServer; @@ -11,15 +13,19 @@ import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; import org.apache.sshd.server.session.ServerSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; @Configuration public class SshConfig { private static final Logger logger = LoggerFactory.getLogger(SshConfig.class); - + @Value("${ssh-server.port}") private int port; @@ -29,6 +35,12 @@ public class SshConfig { @Value("${ssh-server.root.username:root}") private String rootUsername; + @Value("${ssh-server.automatic-replies.location}") + private String repliesProperties; + + @Autowired + ApplicationContext applicationContext; + @Bean public SshServer sshd() throws IOException, NoSuchAlgorithmException { SshServer sshd = SshServer.setUpDefaultServer(); @@ -43,7 +55,18 @@ public class SshConfig { } }); sshd.setShellFactory(new EchoShellFactory()); + sshd.setCommandFactory(command -> applicationContext.getBean(OnetimeCommand.class, command)); sshd.start(); return sshd; } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + public Properties repliesProperties() throws IOException { + Properties prop = new Properties(); + File configFile = new File(repliesProperties); + FileInputStream stream = new FileInputStream(configFile); + prop.load(stream); + return prop; + } }