mirror of
https://github.com/qi4L/JYso.git
synced 2026-09-21 22:40:43 +08:00
feat:文件管理添加上传,输入不存在的链子正确的报错
This commit is contained in:
@@ -90,4 +90,8 @@ export function deleteFile(name) {
|
||||
return api.post('/files/delete', { name })
|
||||
}
|
||||
|
||||
export function uploadFile(formData) {
|
||||
return api.post('/files/upload', formData)
|
||||
}
|
||||
|
||||
export default api
|
||||
|
||||
@@ -906,6 +906,32 @@ select {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
.file-upload-zone {
|
||||
border: 2px dashed var(--border);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
transition: all .2s;
|
||||
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);
|
||||
}
|
||||
.file-upload-zone.drag-over {
|
||||
border-color: var(--primary);
|
||||
background: rgba(99, 102, 241, 0.08);
|
||||
color: var(--primary);
|
||||
}
|
||||
.file-upload-zone.uploading {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*, *::before, *::after {
|
||||
transition-duration: 0ms !important;
|
||||
|
||||
@@ -4,7 +4,8 @@ import { useTheme } from '../context/ThemeContext'
|
||||
import {
|
||||
getStatus, toggleServer, getGadgets,
|
||||
generatePayload as apiGenerate, updateConfig, setAuthToken, getLogs,
|
||||
getFiles, downloadFile, deleteFile as apiDeleteFile
|
||||
getFiles, downloadFile, deleteFile as apiDeleteFile,
|
||||
uploadFile
|
||||
} from '../api'
|
||||
|
||||
export default function Dashboard() {
|
||||
@@ -53,6 +54,9 @@ export default function Dashboard() {
|
||||
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']
|
||||
|
||||
@@ -149,7 +153,7 @@ export default function Dashboard() {
|
||||
setMsg({ success: '', error: res.data.error || 'Generation failed' })
|
||||
}
|
||||
} catch (e) {
|
||||
setMsg({ success: '', error: 'Failed to generate payload' })
|
||||
setMsg({ success: '', error: e.response?.data?.error || 'Failed to generate payload' })
|
||||
} finally { setLoading(false) }
|
||||
}
|
||||
|
||||
@@ -279,6 +283,56 @@ export default function Dashboard() {
|
||||
} 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)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (activeJndiTab !== 'logs') return
|
||||
fetchLogs()
|
||||
@@ -814,6 +868,25 @@ export default function Dashboard() {
|
||||
{filesLoading ? 'Loading...' : 'Refresh'}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className={'file-upload-zone' + (dragOver ? ' drag-over' : '') + (uploading ? ' uploading' : '')}
|
||||
onDragOver={handleDragOver}
|
||||
onDragLeave={handleDragLeave}
|
||||
onDrop={handleDrop}
|
||||
onClick={() => fileInputRef.current?.click()}
|
||||
>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileSelect}
|
||||
/>
|
||||
{uploading ? (
|
||||
<span>Uploading...</span>
|
||||
) : (
|
||||
<span>Drop file here or click to upload</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="file-list">
|
||||
{files.length === 0 ? (
|
||||
<div className="file-empty">No saved files</div>
|
||||
|
||||
@@ -38,7 +38,12 @@ public class Starter {
|
||||
|
||||
if (args[0].equals("-y")) {
|
||||
JYsoMode = true;
|
||||
try {
|
||||
ysoserial.run(args);
|
||||
} catch (Exception e) {
|
||||
System.err.println("[!] " + e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,9 +84,7 @@ public class ysoserial {
|
||||
//载入gadget
|
||||
final Class<? extends ObjectPayload<?>> payloadClass = ObjectPayload.Utils.getPayloadClass(payloadType);
|
||||
if (payloadClass == null) {
|
||||
System.err.println("Invalid payload type '" + payloadType + "'");
|
||||
printUsage(options);
|
||||
System.exit(1);
|
||||
throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.MultipartConfigElement;
|
||||
import java.awt.*;
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
import java.util.EnumSet;
|
||||
@@ -70,7 +71,9 @@ public class JYsoWebApplication {
|
||||
|
||||
context.addServlet(new ServletHolder(new AuthServlet()), "/api/auth/login");
|
||||
|
||||
context.addServlet(new ServletHolder(new JettyApiServlet()), "/api/*");
|
||||
ServletHolder apiHolder = new ServletHolder(new JettyApiServlet());
|
||||
apiHolder.getRegistration().setMultipartConfig(new MultipartConfigElement(""));
|
||||
context.addServlet(apiHolder, "/api/*");
|
||||
|
||||
context.addFilter(new FilterHolder(new SpaFallbackFilter()), "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
|
||||
@@ -11,16 +11,21 @@ import com.qi4l.JYso.gadgets.Config.Config;
|
||||
import com.qi4l.JYso.gadgets.Config.ysoserial;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.MultipartConfig;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.Part;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.*;
|
||||
|
||||
@MultipartConfig
|
||||
public class JettyApiServlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
@@ -58,6 +63,8 @@ public class JettyApiServlet extends HttpServlet {
|
||||
handleFileDownload(req, resp);
|
||||
} else if ("/files/delete".equals(path) && "POST".equalsIgnoreCase(req.getMethod())) {
|
||||
handleFileDelete(req, resp);
|
||||
} else if ("/files/upload".equals(path) && "POST".equalsIgnoreCase(req.getMethod())) {
|
||||
handleFileUpload(req, resp);
|
||||
} else {
|
||||
resp.setStatus(404);
|
||||
resp.getWriter().write("{\"error\":\"Not found\"}");
|
||||
@@ -159,6 +166,34 @@ public class JettyApiServlet extends HttpServlet {
|
||||
resp.getWriter().write(JSON.toJSONString(result));
|
||||
}
|
||||
|
||||
private void handleFileUpload(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
try {
|
||||
Part filePart = req.getPart("file");
|
||||
if (filePart == null || filePart.getSize() == 0) {
|
||||
result.put("success", false);
|
||||
result.put("error", "no file uploaded");
|
||||
resp.getWriter().write(JSON.toJSONString(result));
|
||||
return;
|
||||
}
|
||||
String fileName = filePart.getSubmittedFileName();
|
||||
if (fileName == null || fileName.isEmpty()) {
|
||||
fileName = "uploaded_file";
|
||||
}
|
||||
Path targetPath = Paths.get(fileName);
|
||||
try (InputStream input = filePart.getInputStream()) {
|
||||
Files.copy(input, targetPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
}
|
||||
result.put("success", true);
|
||||
result.put("name", fileName);
|
||||
result.put("size", Files.size(targetPath));
|
||||
} catch (ServletException e) {
|
||||
result.put("success", false);
|
||||
result.put("error", "upload failed: " + e.getMessage());
|
||||
}
|
||||
resp.getWriter().write(JSON.toJSONString(result));
|
||||
}
|
||||
|
||||
private void handleServersStart(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
JSONObject json = readJson(req);
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
@@ -236,27 +271,39 @@ public class JettyApiServlet extends HttpServlet {
|
||||
resp.getWriter().write(JSON.toJSONString(result));
|
||||
return;
|
||||
}
|
||||
boolean nowRunning;
|
||||
boolean nowRunning = false;
|
||||
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;
|
||||
if (LdapServer.isRunning) {
|
||||
LdapServer.stop();
|
||||
} else {
|
||||
new Thread(() -> { try { LdapServer.start(); } catch (Exception ignored) {} }, "ldap-toggler").start();
|
||||
nowRunning = true;
|
||||
}
|
||||
break;
|
||||
case "ldaps":
|
||||
if (LdapsServer.isRunning) LdapsServer.stop();
|
||||
else new Thread(() -> { try { LdapsServer.start(); } catch (Exception ignored) {} }, "ldaps-toggler").start();
|
||||
nowRunning = !LdapsServer.isRunning;
|
||||
if (LdapsServer.isRunning) {
|
||||
LdapsServer.stop();
|
||||
} else {
|
||||
new Thread(() -> { try { LdapsServer.start(); } catch (Exception ignored) {} }, "ldaps-toggler").start();
|
||||
nowRunning = true;
|
||||
}
|
||||
break;
|
||||
case "http":
|
||||
if (HTTPServer.isRunning) HTTPServer.stop();
|
||||
else new Thread(() -> { try { HTTPServer.start(); } catch (Exception ignored) {} }, "http-toggler").start();
|
||||
nowRunning = !HTTPServer.isRunning;
|
||||
if (HTTPServer.isRunning) {
|
||||
HTTPServer.stop();
|
||||
} else {
|
||||
new Thread(() -> { try { HTTPServer.start(); } catch (Exception ignored) {} }, "http-toggler").start();
|
||||
nowRunning = true;
|
||||
}
|
||||
break;
|
||||
case "rmi":
|
||||
if (RMIServer.isRunning) RMIServer.stop();
|
||||
else new Thread(() -> { try { RMIServer.start(); } catch (Exception ignored) {} }, "rmi-toggler").start();
|
||||
nowRunning = !RMIServer.isRunning;
|
||||
if (RMIServer.isRunning) {
|
||||
RMIServer.stop();
|
||||
} else {
|
||||
new Thread(() -> { try { RMIServer.start(); } catch (Exception ignored) {} }, "rmi-toggler").start();
|
||||
nowRunning = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
result.put("success", false);
|
||||
|
||||
Reference in New Issue
Block a user