diff --git a/src/main/frontend/package.json b/src/main/frontend/package.json
index 1cff438..48cf0d1 100644
--- a/src/main/frontend/package.json
+++ b/src/main/frontend/package.json
@@ -10,7 +10,6 @@
},
"dependencies": {
"axios": "^1.6.0",
- "liquid-glass-react": "^1.1.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.28.0"
diff --git a/src/main/frontend/src/api/index.js b/src/main/frontend/src/api/index.js
index f102e88..681563e 100644
--- a/src/main/frontend/src/api/index.js
+++ b/src/main/frontend/src/api/index.js
@@ -44,6 +44,14 @@ export function startServers(data) {
return api.post('/servers/start', data)
}
+export function stopServer(server) {
+ return api.post('/servers/stop', { server })
+}
+
+export function toggleServer(server) {
+ return api.post('/servers/toggle', { server })
+}
+
export function getGadgets() {
return api.get('/gadgets')
}
diff --git a/src/main/frontend/src/index.css b/src/main/frontend/src/index.css
index 023d48c..94976ae 100644
--- a/src/main/frontend/src/index.css
+++ b/src/main/frontend/src/index.css
@@ -31,6 +31,10 @@
--card-radius: 24px;
--btn-radius: 13px;
--input-radius: 13px;
+ --card-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
+ --card-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.04), 0 2px 6px rgba(0, 0, 0, 0.06), 0 0 0 0.5px rgba(0, 0, 0, 0.04);
+ --card-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.05), 0 3px 10px rgba(0, 0, 0, 0.07), 0 0 0 1px rgba(0, 0, 0, 0.04);
+ --card-bg: rgba(255, 255, 255, 0.72);
--font-mono: 'SF Mono', 'JetBrains Mono', 'Fira Code', monospace;
--transition-fast: 200ms cubic-bezier(0.22, 0.1, 0.22, 1);
--transition-fluid: 420ms cubic-bezier(0.22, 0.1, 0.22, 1);
@@ -50,6 +54,10 @@
--success-bg: rgba(48, 209, 88, 0.10);
--danger: #FF453A;
--danger-bg: rgba(255, 69, 58, 0.08);
+ --card-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.20), 0 1px 2px rgba(0, 0, 0, 0.30);
+ --card-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.24), 0 2px 6px rgba(0, 0, 0, 0.32), 0 0 0 0.5px rgba(255, 255, 255, 0.06);
+ --card-shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.28), 0 3px 10px rgba(0, 0, 0, 0.36), 0 0 0 1px rgba(255, 255, 255, 0.06);
+ --card-bg: rgba(28, 28, 30, 0.68);
}
html {
@@ -171,6 +179,89 @@ code, pre, .mono {
.glass-card {
padding: 28px;
+ background: var(--card-bg);
+ backdrop-filter: blur(28px) saturate(180%);
+ -webkit-backdrop-filter: blur(28px) saturate(180%);
+ border-radius: var(--card-radius);
+ box-shadow: var(--card-shadow-md);
+ border: 1px solid var(--border-color);
+ transition: background var(--transition-fluid), box-shadow var(--transition-fluid), border-color var(--transition-fluid), transform var(--transition-fluid);
+}
+
+.mode-segment-control {
+ position: relative;
+ display: flex;
+ align-items: center;
+ background: var(--bg-input);
+ border: 1px solid var(--border-color);
+ border-radius: 12px;
+ padding: 3px;
+ gap: 2px;
+ transition: background var(--transition-fluid), border-color var(--transition-fluid);
+}
+
+.mode-segment-control::before {
+ content: '';
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ width: calc(50% - 4px);
+ height: calc(100% - 6px);
+ background: var(--accent);
+ border-radius: 10px;
+ transition: transform 420ms cubic-bezier(0.34, 1.56, 0.64, 1);
+ box-shadow: 0 2px 12px var(--accent-glow);
+ z-index: 0;
+}
+
+.mode-segment-control.gadget-mode::before {
+ transform: translateX(calc(100% + 2px));
+}
+
+.mode-segment-btn {
+ position: relative;
+ z-index: 1;
+ flex: 1;
+ padding: 7px 16px;
+ border: none;
+ border-radius: 10px;
+ background: transparent;
+ color: var(--text-secondary);
+ font-family: 'Inter', sans-serif;
+ font-size: 13px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: color 320ms cubic-bezier(0.22, 0.1, 0.22, 1);
+ white-space: nowrap;
+ letter-spacing: -0.2px;
+ -webkit-tap-highlight-color: transparent;
+}
+
+.mode-segment-btn:active {
+ transform: scale(0.96);
+ transition: transform 100ms cubic-bezier(0.22, 0.1, 0.22, 1);
+}
+
+.mode-segment-btn.active {
+ color: #FFFFFF;
+}
+
+.section-enter {
+ animation: sectionSlideIn 520ms cubic-bezier(0.22, 0.1, 0, 1) both;
+}
+
+.section-enter:nth-child(2) { animation-delay: 40ms; }
+.section-enter:nth-child(3) { animation-delay: 80ms; }
+
+@keyframes sectionSlideIn {
+ from {
+ opacity: 0;
+ transform: translateY(12px) scale(0.985);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
}
.glass-card h2 {
@@ -201,6 +292,28 @@ code, pre, .mono {
transition: background var(--transition-fluid), border-color var(--transition-fluid);
}
+.status-clickable {
+ cursor: pointer;
+ transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
+}
+
+.status-clickable:hover {
+ background: var(--bg-primary);
+ border-color: var(--accent);
+ box-shadow: var(--card-shadow-sm);
+ transform: translateY(-1px);
+}
+
+.status-clickable:active {
+ transform: scale(0.98);
+ transition: transform 100ms ease;
+}
+
+.status-toggling {
+ opacity: 0.6;
+ pointer-events: none;
+}
+
.status-label {
font-size: 11px;
font-weight: 500;
@@ -389,6 +502,78 @@ code, pre, .mono {
.control-bar .btn { padding: 8px 16px; font-size: 13px; }
+.tab-segment-control {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ background: var(--bg-input);
+ border: 1px solid var(--border-color);
+ border-radius: 11px;
+ padding: 3px;
+ gap: 2px;
+ transition: background var(--transition-fluid), border-color var(--transition-fluid);
+}
+
+.tab-segment-control::before {
+ content: '';
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ width: calc(50% - 4px);
+ height: calc(100% - 6px);
+ background: var(--accent);
+ border-radius: 9px;
+ transition: transform 380ms cubic-bezier(0.34, 1.50, 0.64, 1);
+ box-shadow: 0 2px 10px var(--accent-glow);
+ z-index: 0;
+}
+
+.tab-segment-control.config-tab::before {
+ transform: translateX(calc(100% + 2px));
+}
+
+.tab-segment-btn {
+ position: relative;
+ z-index: 1;
+ padding: 6px 20px;
+ border: none;
+ border-radius: 9px;
+ background: transparent;
+ color: var(--text-secondary);
+ font-family: 'Inter', sans-serif;
+ font-size: 13px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: color 280ms cubic-bezier(0.22, 0.1, 0.22, 1);
+ white-space: nowrap;
+ letter-spacing: -0.2px;
+ -webkit-tap-highlight-color: transparent;
+}
+
+.tab-segment-btn:active {
+ transform: scale(0.96);
+ transition: transform 100ms cubic-bezier(0.22, 0.1, 0.22, 1);
+}
+
+.tab-segment-btn.active {
+ color: #FFFFFF;
+}
+
+.tab-content-enter {
+ animation: tabContentSlide 380ms cubic-bezier(0.22, 0.1, 0, 1) both;
+}
+
+@keyframes tabContentSlide {
+ from {
+ opacity: 0;
+ transform: translateY(6px) scale(0.99);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0) scale(1);
+ }
+}
+
.config-form {
display: grid;
grid-template-columns: 1fr 1fr;
diff --git a/src/main/frontend/src/pages/Dashboard.jsx b/src/main/frontend/src/pages/Dashboard.jsx
index 8c335a7..9f89c88 100644
--- a/src/main/frontend/src/pages/Dashboard.jsx
+++ b/src/main/frontend/src/pages/Dashboard.jsx
@@ -1,32 +1,29 @@
-import { useState, useEffect, useMemo, useRef } from 'react'
+import { useState, useEffect, useMemo, useCallback } from 'react'
import { useNavigate } from 'react-router-dom'
-import LiquidGlass from 'liquid-glass-react'
import { useTheme } from '../context/ThemeContext'
import {
- getStatus, startServers as apiStartServers, getGadgets,
+ getStatus, toggleServer, getGadgets,
generatePayload as apiGenerate, updateConfig, setAuthToken
} from '../api'
export default function Dashboard() {
const navigate = useNavigate()
const { theme, toggleTheme } = useTheme()
- const containerRef = useRef(null)
+ const [mode, setMode] = useState('jndi')
+ const [animKey, setAnimKey] = useState(0)
const [status, setStatus] = useState({})
const [loading, setLoading] = useState(false)
const [msg, setMsg] = useState({ success: '', error: '' })
- const [activeTab, setActiveTab] = useState('servers')
+ const [toggling, setToggling] = useState(null)
const [gadgets, setGadgets] = useState([])
const [gadgetSearch, setGadgetSearch] = useState('')
const [selectedGadget, setSelectedGadget] = useState('')
const [payloadCmd, setPayloadCmd] = useState('')
const [payloadResult, setPayloadResult] = useState('')
- const [serverCfg, setServerCfg] = useState({
- ldap: false, ldaps: false, http: false, rmi: false
- })
-
const [configForm, setConfigForm] = useState({
- ip: '', ldapPort: 1389, ldapsPort: 1669, httpPort: 3456, rmiPort: 1099, codeBase: ''
+ ip: '', ldapPort: 1389, ldapsPort: 1669, httpPort: 3456, rmiPort: 1099,
+ AESkey: '123', user: '', PASSWD: '', TLSProxy: false, keyPass: '', certFile: ''
})
const filteredGadgets = useMemo(() => {
@@ -34,6 +31,13 @@ export default function Dashboard() {
return gadgets.filter(g => g.name.toLowerCase().includes(gadgetSearch.toLowerCase()))
}, [gadgetSearch, gadgets])
+ const switchMode = useCallback((next) => {
+ if (next === mode) return
+ setMode(next)
+ setAnimKey(k => k + 1)
+ setMsg({ success: '', error: '' })
+ }, [mode])
+
async function loadStatus() {
try {
const res = await getStatus()
@@ -45,7 +49,12 @@ export default function Dashboard() {
ldapsPort: res.data.ldapsPort || 1669,
httpPort: res.data.httpPort || 3456,
rmiPort: res.data.rmiPort || 1099,
- codeBase: res.data.codeBase || ''
+ AESkey: res.data.AESkey || '123',
+ user: res.data.user || '',
+ PASSWD: res.data.PASSWD || '',
+ TLSProxy: res.data.TLSProxy || false,
+ keyPass: res.data.keyPass || '',
+ certFile: res.data.certFile || ''
}))
} catch (e) {
if (e.response && e.response.status === 401) {
@@ -62,24 +71,18 @@ export default function Dashboard() {
} catch (e) { /* ignore */ }
}
- async function handleStartServers() {
- setLoading(true)
+ async function handleToggleServer(server) {
+ setToggling(server)
setMsg({ success: '', error: '' })
try {
- const res = await apiStartServers({
- ldap: serverCfg.ldap, ldaps: serverCfg.ldaps,
- http: serverCfg.http, rmi: serverCfg.rmi,
- ip: configForm.ip, ldapPort: configForm.ldapPort,
- ldapsPort: configForm.ldapsPort, httpPort: configForm.httpPort,
- rmiPort: configForm.rmiPort
- })
+ const res = await toggleServer(server)
if (res.data.success) {
- setMsg({ success: 'Servers starting: ' + (res.data.started.join(', ') || 'none'), error: '' })
+ setMsg({ success: server.toUpperCase() + ' ' + (res.data.running ? 'started' : 'stopped'), error: '' })
+ setStatus(res.data.status)
}
- setTimeout(loadStatus, 2000)
} catch (e) {
- setMsg({ success: '', error: 'Failed to start servers' })
- } finally { setLoading(false) }
+ setMsg({ success: '', error: 'Failed to toggle ' + server.toUpperCase() })
+ } finally { setToggling(null) }
}
async function handleSaveConfig() {
@@ -118,27 +121,31 @@ export default function Dashboard() {
useEffect(() => { loadStatus(); loadGadgets() }, [])
- const liquidProps = {
- mouseContainer: containerRef,
- elasticity: 0.07,
- blurAmount: 0.042,
- saturation: 120,
- displacementScale: 36,
- cornerRadius: 24,
- overLight: theme === 'light',
- }
-
return (
-
+
-
+
JYso
+
+
+
+
-
+
- {msg.success && {msg.success}
}
- {msg.error && {msg.error}
}
+ {msg.success && {msg.success}
}
+ {msg.error && {msg.error}
}
-
-
-
Server Status
-
-
- LDAP ({status.ldapPort})
-
- {status.ldapRunning ? 'ONLINE' : 'OFFLINE'}
-
-
-
- LDAPS ({status.ldapsPort})
-
- {status.ldapsRunning ? 'ONLINE' : 'OFFLINE'}
-
-
-
- HTTP ({status.httpPort})
-
- {status.httpRunning ? 'ONLINE' : 'OFFLINE'}
-
-
-
- RMI ({status.rmiPort})
-
- {status.rmiRunning ? 'ONLINE' : 'OFFLINE'}
-
-
-
- IP Address
- {status.ip || '0.0.0.0'}
-
-
- Version
- {status.version || '-'}
-
-
-
-
-
-
-
-
Controls
-
-
-
-
-
-
-
- {activeTab === 'servers' && (
-
-
-
-
-
-
+
+ {mode === 'jndi' && (
+ <>
+
+
Server Status
+
+
handleToggleServer('ldap')}
+ title="Click to toggle LDAP server">
+ LDAP ({status.ldapPort})
+
+ {status.ldapRunning ? 'ONLINE' : 'OFFLINE'}
+
+
+
handleToggleServer('ldaps')}
+ title="Click to toggle LDAPS server">
+ LDAPS ({status.ldapsPort})
+
+ {status.ldapsRunning ? 'ONLINE' : 'OFFLINE'}
+
+
+
handleToggleServer('http')}
+ title="Click to toggle HTTP server">
+ HTTP ({status.httpPort})
+
+ {status.httpRunning ? 'ONLINE' : 'OFFLINE'}
+
+
+
handleToggleServer('rmi')}
+ title="Click to toggle RMI server">
+ RMI ({status.rmiPort})
+
+ {status.rmiRunning ? 'ONLINE' : 'OFFLINE'}
+
+
+
+ IP Address
+ {status.ip || '0.0.0.0'}
+
+
+ Version
+ 1.3.8
+
-
- )}
- {activeTab === 'config' && (
-
+
+
Config
+
+
+ setConfigForm({ ...configForm, ip: e.target.value })} />
+
+
+
+ setConfigForm({ ...configForm, ldapPort: parseInt(e.target.value) || 1389 })} />
+
+
+
+ setConfigForm({ ...configForm, ldapsPort: parseInt(e.target.value) || 1669 })} />
+
+
+
+ setConfigForm({ ...configForm, httpPort: parseInt(e.target.value) || 3456 })} />
+
+
+
+ setConfigForm({ ...configForm, rmiPort: parseInt(e.target.value) || 1099 })} />
+
+
+
+ setConfigForm({ ...configForm, AESkey: e.target.value })} />
+
+
+
+ setConfigForm({ ...configForm, user: e.target.value })} />
+
+
+
+ setConfigForm({ ...configForm, PASSWD: e.target.value })} />
+
+
+
+ setConfigForm({ ...configForm, keyPass: e.target.value })} />
+
+
+
+ setConfigForm({ ...configForm, certFile: e.target.value })} />
+
+
+
+
+
+
- )}
+ >
+ )}
- {activeTab === 'payload' && (
+ {mode === 'gadget' && (
+
+
Payload Generator
@@ -320,9 +321,9 @@ export default function Dashboard() {
)}
- )}
-
-
+
+ )}
+
)
diff --git a/src/main/frontend/src/pages/Login.jsx b/src/main/frontend/src/pages/Login.jsx
index 6b60227..919a447 100644
--- a/src/main/frontend/src/pages/Login.jsx
+++ b/src/main/frontend/src/pages/Login.jsx
@@ -1,13 +1,11 @@
-import { useState, useRef } from 'react'
+import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
-import LiquidGlass from 'liquid-glass-react'
import { login, setAuthToken } from '../api'
import { useTheme } from '../context/ThemeContext'
export default function Login() {
const navigate = useNavigate()
const { theme, toggleTheme } = useTheme()
- const containerRef = useRef(null)
const [username, setUsername] = useState('qi')
const [password, setPassword] = useState('')
const [error, setError] = useState('')
@@ -44,7 +42,7 @@ export default function Login() {
}
return (
-
+
-
+
@@ -96,7 +84,7 @@ export default function Login() {
-
+
)
}
diff --git a/src/main/java/com/qi4l/JYso/HTTPServer.java b/src/main/java/com/qi4l/JYso/HTTPServer.java
index 95059b5..8d8adae 100644
--- a/src/main/java/com/qi4l/JYso/HTTPServer.java
+++ b/src/main/java/com/qi4l/JYso/HTTPServer.java
@@ -30,10 +30,11 @@ public class HTTPServer {
private static final Logger log = LogManager.getLogger(HTTPServer.class);
public static boolean isRunning = false;
public static String cwd = System.getProperty("user.dir");
+ private static HttpServer httpServer;
public static void start() throws IOException {
- HttpServer httpServer = HttpServer.create(new InetSocketAddress(Config.httpPort), 0);
+ httpServer = HttpServer.create(new InetSocketAddress(Config.httpPort), 0);
httpServer.createContext("/", httpExchange -> {
try {
System.out.println(ansi().render("@|green [+]|@ New HTTP Request From >>" + httpExchange.getRemoteAddress() + " " + httpExchange.getRequestURI()));
@@ -82,6 +83,14 @@ public class HTTPServer {
System.out.println(ansi().render("@|green [+]|@ HTTP Server Start Listening on >> " + Config.httpPort + "..."));
}
+ public static void stop() {
+ if (httpServer != null) {
+ httpServer.stop(0);
+ isRunning = false;
+ System.out.println(ansi().render("@|yellow [!]|@ HTTP Server stopped"));
+ }
+ }
+
private static void handleFileRequest(HttpExchange exchange) throws Exception {
System.out.println("[-] 请求的后缀不对");
String path = exchange.getRequestURI().getPath();
diff --git a/src/main/java/com/qi4l/JYso/LdapServer.java b/src/main/java/com/qi4l/JYso/LdapServer.java
index be81ea6..ab6142a 100644
--- a/src/main/java/com/qi4l/JYso/LdapServer.java
+++ b/src/main/java/com/qi4l/JYso/LdapServer.java
@@ -31,6 +31,7 @@ public class LdapServer extends InMemoryOperationInterceptor {
private static final Logger log = LogManager.getLogger(LdapServer.class);
public static TreeMap
routes = new TreeMap<>();
public static boolean isRunning = false;
+ private static InMemoryDirectoryServer ds;
public LdapServer() throws Exception {
@@ -71,7 +72,7 @@ public class LdapServer extends InMemoryOperationInterceptor {
//添加操作拦截器
//将提供的操作拦截器添加到操作拦截器列表中,该列表可用于在请求被内存目录服务器处理之前转换请求,和/或在响应返回给客户端之前转换响应。
serverConfig.addInMemoryOperationInterceptor(new LdapServer());
- InMemoryDirectoryServer ds = new InMemoryDirectoryServer(serverConfig);
+ ds = new InMemoryDirectoryServer(serverConfig);
ds.startListening();
isRunning = true;
System.out.println(ansi().render("@|green [+]|@ LDAP Server Start Listening on >> " + Config.ldapPort + "..."));
@@ -80,6 +81,14 @@ public class LdapServer extends InMemoryOperationInterceptor {
}
}
+ public static void stop() {
+ if (ds != null) {
+ ds.shutDown(true);
+ isRunning = false;
+ System.out.println(ansi().render("@|yellow [!]|@ LDAP Server stopped"));
+ }
+ }
+
@Override
public void processSearchResult(InMemoryInterceptedSearchResult result) {
String base;
diff --git a/src/main/java/com/qi4l/JYso/LdapsServer.java b/src/main/java/com/qi4l/JYso/LdapsServer.java
index 6fa8f0f..98acc23 100644
--- a/src/main/java/com/qi4l/JYso/LdapsServer.java
+++ b/src/main/java/com/qi4l/JYso/LdapsServer.java
@@ -15,6 +15,7 @@ import static org.fusesource.jansi.Ansi.ansi;
public class LdapsServer {
private static final Logger log = LogManager.getLogger(LdapsServer.class);
public static boolean isRunning = false;
+ private static InMemoryDirectoryServer ds;
private final String certFile;
private final String keyPass;
@@ -50,7 +51,7 @@ public class LdapsServer {
));
config.addInMemoryOperationInterceptor(new LdapServer());
- InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
+ ds = new InMemoryDirectoryServer(config);
ds.startListening();
isRunning = true;
System.out.println(ansi().render("@|green [+]|@ LDAPS Server Start Listening on >> " + Config.ldapsPort + "..."));
@@ -58,4 +59,12 @@ public class LdapsServer {
log.error("e: ", e);
}
}
+
+ public static void stop() {
+ if (ds != null) {
+ ds.shutDown(true);
+ isRunning = false;
+ System.out.println(ansi().render("@|yellow [!]|@ LDAPS Server stopped"));
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/qi4l/JYso/RMIServer.java b/src/main/java/com/qi4l/JYso/RMIServer.java
index 28d8e39..86bfb33 100644
--- a/src/main/java/com/qi4l/JYso/RMIServer.java
+++ b/src/main/java/com/qi4l/JYso/RMIServer.java
@@ -50,6 +50,7 @@ import static org.fusesource.jansi.Ansi.ansi;
public class RMIServer implements Runnable {
public static boolean isRunning = false;
+ private static RMIServer instance;
private final ServerSocket ss;
private final Object waitLock = new Object();
@@ -67,15 +68,23 @@ public class RMIServer implements Runnable {
try {
System.out.println(ansi().render("@|green [+]|@ RMI Server Start Listening on >> " + rmiPort + "..."));
- RMIServer c = new RMIServer(rmiPort, new URL(url));
+ instance = new RMIServer(rmiPort, new URL(url));
isRunning = true;
- c.run();
+ instance.run();
} catch (Exception e) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
}
+ public static void stop() {
+ if (instance != null) {
+ instance.close();
+ isRunning = false;
+ System.out.println(ansi().render("@|yellow [!]|@ RMI Server stopped"));
+ }
+ }
+
private static void handleDGC(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.readInt(); // method
ois.readLong(); // hash
diff --git a/src/main/java/com/qi4l/JYso/gadgets/Config/Config.java b/src/main/java/com/qi4l/JYso/gadgets/Config/Config.java
index cabc48c..129e2df 100644
--- a/src/main/java/com/qi4l/JYso/gadgets/Config/Config.java
+++ b/src/main/java/com/qi4l/JYso/gadgets/Config/Config.java
@@ -29,8 +29,6 @@ public class Config {
@Parameter(names = {"-hP", "--httpPort"}, description = "Http bind port", order = 3)
public static int httpPort = 3456;
- @Parameter(names = {"-c", " --command"}, help = true, description = "RMI this command")
- public static String command = "whoami";
@Parameter(names = {"-v", " --version"}, help = true, description = "Show version", order = 5)
public static boolean showVersion;
@Parameter(names = {"-ga", " --gadgets"}, help = true, description = "Show gadgets", order = 5)
diff --git a/src/main/java/com/qi4l/JYso/web/JYsoWebApplication.java b/src/main/java/com/qi4l/JYso/web/JYsoWebApplication.java
index 660a226..73047af 100644
--- a/src/main/java/com/qi4l/JYso/web/JYsoWebApplication.java
+++ b/src/main/java/com/qi4l/JYso/web/JYsoWebApplication.java
@@ -15,6 +15,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
+import java.awt.*;
+import java.awt.datatransfer.StringSelection;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
@@ -52,6 +54,8 @@ public class JYsoWebApplication {
System.out.println(ansi().render("@|yellow [+]|@ Password: " + webPassword));
System.out.println(ansi().render("@|yellow [+]|@ ============================================"));
+ copyToClipboard(webPassword);
+
startJndiServers(args);
Properties props = new Properties();
@@ -77,6 +81,19 @@ public class JYsoWebApplication {
}
}
+ private static void copyToClipboard(String text) {
+ try {
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
+ new StringSelection(text), null
+ );
+ System.out.println(ansi().render("@|cyan [+]|@ Password copied to clipboard"));
+ } catch (HeadlessException e) {
+ // headless environment, clipboard unavailable
+ } catch (Exception e) {
+ System.out.println(ansi().render("@|yellow [!]|@ Could not copy to clipboard: " + e.getMessage()));
+ }
+ }
+
private static String[] filterWebArgs(String[] args) {
java.util.List filtered = new java.util.ArrayList<>();
for (int i = 0; i < args.length; i++) {
diff --git a/src/main/java/com/qi4l/JYso/web/controller/ApiController.java b/src/main/java/com/qi4l/JYso/web/controller/ApiController.java
index fef4259..ea5086e 100644
--- a/src/main/java/com/qi4l/JYso/web/controller/ApiController.java
+++ b/src/main/java/com/qi4l/JYso/web/controller/ApiController.java
@@ -29,7 +29,13 @@ public class ApiController {
status.put("httpPort", Config.httpPort);
status.put("rmiPort", Config.rmiPort);
status.put("codeBase", Config.codeBase);
- status.put("version", "1.3.7");
+ status.put("AESkey", Config.AESkey);
+ status.put("user", Config.USER);
+ status.put("PASSWD", Config.PASSWD);
+ status.put("TLSProxy", Config.TLSProxy);
+ status.put("keyPass", Config.keyPass);
+ status.put("certFile", Config.certFile);
+ status.put("version", "1.3.8");
return status;
}
@@ -81,6 +87,83 @@ public class ApiController {
return result;
}
+ @PostMapping("/servers/stop")
+ public Map stopServer(@RequestBody Map body) {
+ Map result = new LinkedHashMap<>();
+ String server = (String) body.get("server");
+ if (server == null) {
+ result.put("success", false);
+ result.put("error", "server name required");
+ return result;
+ }
+ switch (server.toLowerCase()) {
+ case "ldap":
+ LdapServer.stop();
+ break;
+ case "ldaps":
+ LdapsServer.stop();
+ break;
+ case "http":
+ HTTPServer.stop();
+ break;
+ case "rmi":
+ RMIServer.stop();
+ break;
+ default:
+ result.put("success", false);
+ result.put("error", "unknown server: " + server);
+ return result;
+ }
+ result.put("success", true);
+ result.put("server", server);
+ result.put("status", getStatus());
+ return result;
+ }
+
+ @PostMapping("/servers/toggle")
+ public Map toggleServer(@RequestBody Map body) {
+ Map result = new LinkedHashMap<>();
+ String server = (String) body.get("server");
+ if (server == null) {
+ result.put("success", false);
+ result.put("error", "server name required");
+ return result;
+ }
+ boolean nowRunning;
+ switch (server.toLowerCase()) {
+ case "ldap":
+ if (LdapServer.isRunning) LdapServer.stop();
+ else new Thread(() -> { try { LdapServer.start(); } catch (Exception ignored) {} }, "ldap-toggler").start();
+ nowRunning = !LdapServer.isRunning;
+ break;
+ case "ldaps":
+ if (LdapsServer.isRunning) LdapsServer.stop();
+ else new Thread(() -> { try { LdapsServer.start(); } catch (Exception ignored) {} }, "ldaps-toggler").start();
+ nowRunning = !LdapsServer.isRunning;
+ break;
+ case "http":
+ if (HTTPServer.isRunning) HTTPServer.stop();
+ else new Thread(() -> { try { HTTPServer.start(); } catch (Exception ignored) {} }, "http-toggler").start();
+ nowRunning = !HTTPServer.isRunning;
+ break;
+ case "rmi":
+ if (RMIServer.isRunning) RMIServer.stop();
+ else new Thread(() -> { try { RMIServer.start(); } catch (Exception ignored) {} }, "rmi-toggler").start();
+ nowRunning = !RMIServer.isRunning;
+ break;
+ default:
+ result.put("success", false);
+ result.put("error", "unknown server: " + server);
+ return result;
+ }
+ try { Thread.sleep(800); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
+ result.put("success", true);
+ result.put("server", server);
+ result.put("running", nowRunning);
+ result.put("status", getStatus());
+ return result;
+ }
+
@GetMapping("/gadgets")
public List