diff --git a/.gitignore b/.gitignore
index 8801278..da7a791 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
/target/
/.classpath
/.project
-/.settings
\ No newline at end of file
+/.settings/
+/logs/
diff --git a/conf/hash-replies.properties b/conf/hash-replies.properties
new file mode 100644
index 0000000..7b07a35
--- /dev/null
+++ b/conf/hash-replies.properties
@@ -0,0 +1,20 @@
+prompt=root@mail.vidconnect.cyou$
+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=root
+4DE8A3B5E72E54D9D2A70BD43CB5EA9E=Model:\t\t0
+99EFF9F4022855955653078ECB2B4CE4=1.9G
+39B28F3F76277A5E25665A3DBB12CC5B=3942 2493 512 9 936 1275
+B9B7DA613BBB90640EB8E5F657E41E6B=-rwxr-xr-x 1 root root 123K Jan 18 2018 /bin/ls
+F806FB8A02384A22ECC110F111367FF7=crontabs/root/: fopen: Permission denied
+C1B46A786F0DD463D37DF505EA57FCE4=Permission denied
+36CAB7DA5AB930336E239DD8008DCBBD=Permission denied
+w= 12:28:36 up 654 days, 1:37, 1 user, load average: 0.00, 0.00, 0.00\r\nUSER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT\r\nroot pts/0 58.176.72.32 10:46 1.00s 13.14s 0.00s w
+top=Permission denied
+43AEB525EBC517BAF8C01E7AC83F63CE=aarch64
+3AA823F5C5095BD60BE4AA37D603BBA4= 0 0 0 -
+8B456C4EB5A75DA148EAD2E83B334E5E=Permission denied
+FE5B6F84E749B84114423D5AD1A11034=
+83809E84C1396C58D4156E8FF7782299=[ Uname ] 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\r\n[ Uptime ] 15:23:06 up 655 days, 4:32, 1 user, load average: 0.00, 0.00, 0.00\r\n
+chpasswd=Password updated
\ No newline at end of file
diff --git a/conf/log4j2.xml b/conf/log4j2.xml
index 8fb6fff..6b237ca 100644
--- a/conf/log4j2.xml
+++ b/conf/log4j2.xml
@@ -14,10 +14,22 @@
+
+
+
+
+
+
-
-
+
+
+
+
+
\ No newline at end of file
diff --git a/conf/regex-mapping.properties b/conf/regex-mapping.properties
new file mode 100644
index 0000000..b78553f
--- /dev/null
+++ b/conf/regex-mapping.properties
@@ -0,0 +1 @@
+.*chpasswd.*=chpasswd
\ No newline at end of file
diff --git a/conf/replies.properties b/conf/replies.properties
deleted file mode 100644
index 015e2db..0000000
--- a/conf/replies.properties
+++ /dev/null
@@ -1,7 +0,0 @@
-prompt=root@localhost$
-5BAABD7C4581F90088133C0E945302C2=\t0\t0\t0 -
-uname=Linux
-9DD46246144D353C914D7572AEDF8EA6=Linux localhost 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:10 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux
-whoami=root
-4DE8A3B5E72E54D9D2A70BD43CB5EA9E=Model:\t\t0
-99EFF9F4022855955653078ECB2B4CE4=1.9G
diff --git a/conf/springboot.yml b/conf/springboot.yml
index 2f8d567..6fd22eb 100644
--- a/conf/springboot.yml
+++ b/conf/springboot.yml
@@ -2,5 +2,8 @@ ssh-server:
port: 1022
private-key:
location: "conf/private.key"
- automatic-replies:
- location: "conf/replies.properties"
+ hash-replies:
+ location: "conf/hash-replies.properties"
+ regex-mapping:
+ location: "conf/regex-mapping.properties"
+
diff --git a/pom.xml b/pom.xml
index cface4a..3986876 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
com.example.sshd
echo-sshd-server
- 1.0.4
+ 1.1.0
ECHO SSH SERVER
Learning Apache Mina SSHD library
diff --git a/src/main/java/com/example/sshd/config/SshConfig.java b/src/main/java/com/example/sshd/config/SshConfig.java
index 1ae0db6..14ad355 100644
--- a/src/main/java/com/example/sshd/config/SshConfig.java
+++ b/src/main/java/com/example/sshd/config/SshConfig.java
@@ -21,6 +21,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
+import com.example.sshd.core.EchoShellFactory;
+import com.example.sshd.core.OnetimeCommand;
+
@Configuration
public class SshConfig {
@@ -35,8 +38,11 @@ public class SshConfig {
@Value("${ssh-server.root.username:root}")
private String rootUsername;
- @Value("${ssh-server.automatic-replies.location}")
- private String repliesProperties;
+ @Value("${ssh-server.hash-replies.location}")
+ private String hashReplies;
+
+ @Value("${ssh-server.regex-mapping.location}")
+ private String regexMapping;
@Autowired
ApplicationContext applicationContext;
@@ -62,9 +68,19 @@ public class SshConfig {
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
- public Properties repliesProperties() throws IOException {
+ public Properties hashReplies() throws IOException {
+ Properties prop = new Properties();
+ File configFile = new File(hashReplies);
+ FileInputStream stream = new FileInputStream(configFile);
+ prop.load(stream);
+ return prop;
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
+ public Properties regexMapping() throws IOException {
Properties prop = new Properties();
- File configFile = new File(repliesProperties);
+ File configFile = new File(regexMapping);
FileInputStream stream = new FileInputStream(configFile);
prop.load(stream);
return prop;
diff --git a/src/main/java/com/example/sshd/config/EchoShellFactory.java b/src/main/java/com/example/sshd/core/EchoShellFactory.java
similarity index 81%
rename from src/main/java/com/example/sshd/config/EchoShellFactory.java
rename to src/main/java/com/example/sshd/core/EchoShellFactory.java
index 2e5c09c..5e6eaf5 100644
--- a/src/main/java/com/example/sshd/config/EchoShellFactory.java
+++ b/src/main/java/com/example/sshd/core/EchoShellFactory.java
@@ -1,4 +1,4 @@
-package com.example.sshd.config;
+package com.example.sshd.core;
import java.io.BufferedReader;
import java.io.IOException;
@@ -26,17 +26,20 @@ public class EchoShellFactory implements Factory {
private static final Logger logger = LoggerFactory.getLogger(EchoShellFactory.class);
@Autowired
- Properties repliesProperties;
+ Properties hashReplies;
+
+ @Autowired
+ Properties regexMapping;
@Autowired
ApplicationContext applicationContext;
@Override
public Command create() {
- return new EchoShell(repliesProperties);
+ return new EchoShell();
}
- public static class EchoShell implements Command, Runnable {
+ public class EchoShell implements Command, Runnable {
private InputStream in;
private OutputStream out;
@@ -44,11 +47,6 @@ public class EchoShellFactory implements Factory {
private ExitCallback callback;
private Environment environment;
private Thread thread;
- private Properties repliesProperties;
-
- public EchoShell(Properties repliesProperties) {
- this.repliesProperties = repliesProperties;
- }
public InputStream getIn() {
return in;
@@ -100,7 +98,7 @@ public class EchoShellFactory implements Factory {
@Override
public void run() {
- String prompt = repliesProperties.getProperty("prompt", "$ ");
+ String prompt = hashReplies.getProperty("prompt", "$ ");
try {
out.write(prompt.getBytes());
out.flush();
@@ -111,7 +109,8 @@ public class EchoShellFactory implements Factory {
while (!Thread.currentThread().isInterrupted()) {
int s = r.read();
if (s == 13 || s == 10) {
- if (!ReplyUtil.replyToCommand(repliesProperties, command, out, prompt)) {
+ if (!ReplyUtil.replyToCommand(command, out, prompt, hashReplies, regexMapping)) {
+ out.flush();
return;
}
command = "";
diff --git a/src/main/java/com/example/sshd/config/OnetimeCommand.java b/src/main/java/com/example/sshd/core/OnetimeCommand.java
similarity index 86%
rename from src/main/java/com/example/sshd/config/OnetimeCommand.java
rename to src/main/java/com/example/sshd/core/OnetimeCommand.java
index 88b87b1..966a4a4 100644
--- a/src/main/java/com/example/sshd/config/OnetimeCommand.java
+++ b/src/main/java/com/example/sshd/core/OnetimeCommand.java
@@ -1,4 +1,4 @@
-package com.example.sshd.config;
+package com.example.sshd.core;
import java.io.IOException;
import java.io.InputStream;
@@ -20,7 +20,10 @@ import com.example.sshd.util.ReplyUtil;
public class OnetimeCommand implements Command {
@Autowired
- Properties repliesProperties;
+ Properties hashReplies;
+
+ @Autowired
+ Properties regexMapping;
private InputStream in;
private OutputStream out;
@@ -72,7 +75,7 @@ public class OnetimeCommand implements Command {
@Override
public void start(Environment env) throws IOException {
environment = env;
- ReplyUtil.replyToCommand(repliesProperties, command, out, "");
+ ReplyUtil.replyToCommand(command, out, "", hashReplies, regexMapping);
out.flush();
callback.onExit(0);
}
diff --git a/src/main/java/com/example/sshd/util/ReplyUtil.java b/src/main/java/com/example/sshd/util/ReplyUtil.java
index 7c952d7..238c14b 100644
--- a/src/main/java/com/example/sshd/util/ReplyUtil.java
+++ b/src/main/java/com/example/sshd/util/ReplyUtil.java
@@ -2,19 +2,22 @@ package com.example.sshd.util;
import java.io.IOException;
import java.io.OutputStream;
+import java.util.Optional;
import java.util.Properties;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReplyUtil {
private static final Logger logger = LoggerFactory.getLogger(ReplyUtil.class);
+ private static final Logger notFoundLogger = LoggerFactory.getLogger("not_found");
- public static boolean replyToCommand(Properties repliesProperties, String command, OutputStream out, String prompt)
- throws IOException {
+ public static boolean replyToCommand(String command, OutputStream out, String prompt, Properties hashReplies,
+ Properties regexMapping) throws IOException {
String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase();
@@ -22,19 +25,31 @@ public class ReplyUtil {
logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim());
out.write(("\r\nExiting...\r\n").getBytes());
return false;
- } else if (repliesProperties.containsKey(command.trim())) {
+ } else if (hashReplies.containsKey(command.trim())) {
logger.info("[{}] Known command detected: {}", cmdHash, command.trim());
- String reply = repliesProperties.getProperty(command.trim()).replace("\\r", "\r").replace("\\n", "\n")
+ String reply = hashReplies.getProperty(command.trim()).replace("\\r", "\r").replace("\\n", "\n")
.replace("\\t", "\t");
out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes());
- } else if (repliesProperties.containsKey(cmdHash)) {
+ } else if (hashReplies.containsKey(cmdHash)) {
logger.info("[{}] Known command-hash detected: {}", cmdHash, command.trim());
- String reply = repliesProperties.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n")
- .replace("\\t", "\t");
+ String reply = hashReplies.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n").replace("\\t",
+ "\t");
out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes());
} else {
- logger.info("[{}] Command not found: {}", cmdHash, command.trim());
- out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt).getBytes());
+ Optional> o = regexMapping.entrySet().stream()
+ .filter(e -> command.trim().matches(((String) e.getKey())))
+ .map(e -> Pair.of((String) e.getKey(), (String) e.getValue())).findAny();
+ if (o.isPresent()) {
+ logger.info("[{}] Known pattern detected: {} ({})", cmdHash, command.trim(), o.get());
+ String reply = hashReplies.getProperty(o.get().getRight(), "").replace("\\r", "\r").replace("\\n", "\n")
+ .replace("\\t", "\t");
+ out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes());
+ } else {
+ logger.info("[{}] Command not found: {}", cmdHash, command.trim());
+ notFoundLogger.info("[{}] Command not found: {}", cmdHash, command.trim());
+ out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt)
+ .getBytes());
+ }
}
return true;
}