V1.1.0 RegEx Pattern Matching

master
Ng Yat Yan 1 month ago
parent 9417a7b022
commit 53e9f25a1d

3
.gitignore vendored

@ -1,4 +1,5 @@
/target/ /target/
/.classpath /.classpath
/.project /.project
/.settings /.settings/
/logs/

@ -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

@ -14,10 +14,22 @@
<TimeBasedTriggeringPolicy interval="1" modulate="true" /> <TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies> </Policies>
</RollingFile> </RollingFile>
<RollingFile name="LogToNotFound"
filePattern="logs/not_found.%d{yyyy-MM-dd}.log"
immediateFlush="true">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %p [%t] %c : %m%n" />
<Policies>
<TimeBasedTriggeringPolicy interval="1" modulate="true" />
</Policies>
</RollingFile>
</Appenders> </Appenders>
<Loggers> <Loggers>
<Root level="debug"> <Logger name="not_found" level="info" additivity="false">
<AppenderRef ref="LogToConsole" /> <AppenderRef ref="LogToNotFound" />
</Logger>
<Root level="info">
<AppenderRef ref="LogToFile" />
</Root> </Root>
</Loggers> </Loggers>
</Configuration> </Configuration>

@ -0,0 +1 @@
.*chpasswd.*=chpasswd

@ -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

@ -2,5 +2,8 @@ ssh-server:
port: 1022 port: 1022
private-key: private-key:
location: "conf/private.key" location: "conf/private.key"
automatic-replies: hash-replies:
location: "conf/replies.properties" location: "conf/hash-replies.properties"
regex-mapping:
location: "conf/regex-mapping.properties"

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.example.sshd</groupId> <groupId>com.example.sshd</groupId>
<artifactId>echo-sshd-server</artifactId> <artifactId>echo-sshd-server</artifactId>
<version>1.0.4</version> <version>1.1.0</version>
<name>ECHO SSH SERVER</name> <name>ECHO SSH SERVER</name>
<description>Learning Apache Mina SSHD library</description> <description>Learning Apache Mina SSHD library</description>
<parent> <parent>

@ -21,6 +21,9 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import com.example.sshd.core.EchoShellFactory;
import com.example.sshd.core.OnetimeCommand;
@Configuration @Configuration
public class SshConfig { public class SshConfig {
@ -35,8 +38,11 @@ public class SshConfig {
@Value("${ssh-server.root.username:root}") @Value("${ssh-server.root.username:root}")
private String rootUsername; private String rootUsername;
@Value("${ssh-server.automatic-replies.location}") @Value("${ssh-server.hash-replies.location}")
private String repliesProperties; private String hashReplies;
@Value("${ssh-server.regex-mapping.location}")
private String regexMapping;
@Autowired @Autowired
ApplicationContext applicationContext; ApplicationContext applicationContext;
@ -62,9 +68,19 @@ public class SshConfig {
@Bean @Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) @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(); Properties prop = new Properties();
File configFile = new File(repliesProperties); File configFile = new File(regexMapping);
FileInputStream stream = new FileInputStream(configFile); FileInputStream stream = new FileInputStream(configFile);
prop.load(stream); prop.load(stream);
return prop; return prop;

@ -1,4 +1,4 @@
package com.example.sshd.config; package com.example.sshd.core;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@ -26,17 +26,20 @@ public class EchoShellFactory implements Factory<Command> {
private static final Logger logger = LoggerFactory.getLogger(EchoShellFactory.class); private static final Logger logger = LoggerFactory.getLogger(EchoShellFactory.class);
@Autowired @Autowired
Properties repliesProperties; Properties hashReplies;
@Autowired
Properties regexMapping;
@Autowired @Autowired
ApplicationContext applicationContext; ApplicationContext applicationContext;
@Override @Override
public Command create() { 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 InputStream in;
private OutputStream out; private OutputStream out;
@ -44,11 +47,6 @@ public class EchoShellFactory implements Factory<Command> {
private ExitCallback callback; private ExitCallback callback;
private Environment environment; private Environment environment;
private Thread thread; private Thread thread;
private Properties repliesProperties;
public EchoShell(Properties repliesProperties) {
this.repliesProperties = repliesProperties;
}
public InputStream getIn() { public InputStream getIn() {
return in; return in;
@ -100,7 +98,7 @@ public class EchoShellFactory implements Factory<Command> {
@Override @Override
public void run() { public void run() {
String prompt = repliesProperties.getProperty("prompt", "$ "); String prompt = hashReplies.getProperty("prompt", "$ ");
try { try {
out.write(prompt.getBytes()); out.write(prompt.getBytes());
out.flush(); out.flush();
@ -111,7 +109,8 @@ public class EchoShellFactory implements Factory<Command> {
while (!Thread.currentThread().isInterrupted()) { while (!Thread.currentThread().isInterrupted()) {
int s = r.read(); int s = r.read();
if (s == 13 || s == 10) { if (s == 13 || s == 10) {
if (!ReplyUtil.replyToCommand(repliesProperties, command, out, prompt)) { if (!ReplyUtil.replyToCommand(command, out, prompt, hashReplies, regexMapping)) {
out.flush();
return; return;
} }
command = ""; command = "";

@ -1,4 +1,4 @@
package com.example.sshd.config; package com.example.sshd.core;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -20,7 +20,10 @@ import com.example.sshd.util.ReplyUtil;
public class OnetimeCommand implements Command { public class OnetimeCommand implements Command {
@Autowired @Autowired
Properties repliesProperties; Properties hashReplies;
@Autowired
Properties regexMapping;
private InputStream in; private InputStream in;
private OutputStream out; private OutputStream out;
@ -72,7 +75,7 @@ public class OnetimeCommand implements Command {
@Override @Override
public void start(Environment env) throws IOException { public void start(Environment env) throws IOException {
environment = env; environment = env;
ReplyUtil.replyToCommand(repliesProperties, command, out, ""); ReplyUtil.replyToCommand(command, out, "", hashReplies, regexMapping);
out.flush(); out.flush();
callback.onExit(0); callback.onExit(0);
} }

@ -2,19 +2,22 @@ package com.example.sshd.util;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Optional;
import java.util.Properties; import java.util.Properties;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
public class ReplyUtil { public class ReplyUtil {
private static final Logger logger = LoggerFactory.getLogger(ReplyUtil.class); 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) public static boolean replyToCommand(String command, OutputStream out, String prompt, Properties hashReplies,
throws IOException { Properties regexMapping) throws IOException {
String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase(); String cmdHash = DigestUtils.md5Hex(command.trim()).toUpperCase();
@ -22,19 +25,31 @@ public class ReplyUtil {
logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim()); logger.info("[{}] Exiting command detected: {}", cmdHash, command.trim());
out.write(("\r\nExiting...\r\n").getBytes()); out.write(("\r\nExiting...\r\n").getBytes());
return false; return false;
} else if (repliesProperties.containsKey(command.trim())) { } else if (hashReplies.containsKey(command.trim())) {
logger.info("[{}] Known command detected: {}", cmdHash, 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"); .replace("\\t", "\t");
out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); 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()); logger.info("[{}] Known command-hash detected: {}", cmdHash, command.trim());
String reply = repliesProperties.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n") String reply = hashReplies.getProperty(cmdHash).replace("\\r", "\r").replace("\\n", "\n").replace("\\t",
.replace("\\t", "\t"); "\t");
out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes()); out.write(String.format("\r\n%s\r\n%s", reply, prompt).getBytes());
} else { } else {
logger.info("[{}] Command not found: {}", cmdHash, command.trim()); Optional<Pair<String, String>> o = regexMapping.entrySet().stream()
out.write(String.format("\r\nCommand '%s' not found. Try 'exit'.\r\n%s", command.trim(), prompt).getBytes()); .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; return true;
} }

Loading…
Cancel
Save