mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-01 00:27:35 +02:00
Add files via upload
This commit is contained in:
@@ -721,15 +721,22 @@ func (h *WebShellHandler) Exec(c *gin.Context) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "url and command are required"})
|
||||
return
|
||||
}
|
||||
conn, allowed := h.authorizedWebshellConnection(c, req.ConnectionID, req.URL)
|
||||
if !allowed {
|
||||
// Pre-save connectivity tests send form credentials without connection_id.
|
||||
// Saved connections must go through resource ACL; DB credentials are authoritative.
|
||||
if cid := strings.TrimSpace(req.ConnectionID); cid != "" {
|
||||
conn, allowed := h.authorizedWebshellConnection(c, cid, req.URL)
|
||||
if !allowed {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "无权访问该资源"})
|
||||
return
|
||||
}
|
||||
// Never let a caller pair an authorized ID with attacker-controlled
|
||||
// transport credentials or a URL.
|
||||
req.URL, req.Password, req.Type = conn.URL, conn.Password, conn.Type
|
||||
req.Method, req.CmdParam, req.Encoding = conn.Method, conn.CmdParam, conn.Encoding
|
||||
} else if !security.SessionHasPermission(c, "webshell:write") {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "无权访问该资源"})
|
||||
return
|
||||
}
|
||||
// The database record is authoritative. Never let a caller pair an
|
||||
// authorized ID with attacker-controlled transport credentials or a URL.
|
||||
req.URL, req.Password, req.Type = conn.URL, conn.Password, conn.Type
|
||||
req.Method, req.CmdParam, req.Encoding = conn.Method, conn.CmdParam, conn.Encoding
|
||||
|
||||
parsed, err := url.Parse(req.URL)
|
||||
if err != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") {
|
||||
@@ -823,13 +830,18 @@ func (h *WebShellHandler) FileOp(c *gin.Context) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "url and action are required"})
|
||||
return
|
||||
}
|
||||
conn, allowed := h.authorizedWebshellConnection(c, req.ConnectionID, req.URL)
|
||||
if !allowed {
|
||||
if cid := strings.TrimSpace(req.ConnectionID); cid != "" {
|
||||
conn, allowed := h.authorizedWebshellConnection(c, cid, req.URL)
|
||||
if !allowed {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "无权访问该资源"})
|
||||
return
|
||||
}
|
||||
req.URL, req.Password, req.Type = conn.URL, conn.Password, conn.Type
|
||||
req.Method, req.CmdParam, req.Encoding, req.OS = conn.Method, conn.CmdParam, conn.Encoding, conn.OS
|
||||
} else if !security.SessionHasPermission(c, "webshell:write") {
|
||||
c.JSON(http.StatusForbidden, gin.H{"error": "无权访问该资源"})
|
||||
return
|
||||
}
|
||||
req.URL, req.Password, req.Type = conn.URL, conn.Password, conn.Type
|
||||
req.Method, req.CmdParam, req.Encoding, req.OS = conn.Method, conn.CmdParam, conn.Encoding, conn.OS
|
||||
|
||||
parsed, err := url.Parse(req.URL)
|
||||
if err != nil || (parsed.Scheme != "http" && parsed.Scheme != "https") {
|
||||
|
||||
@@ -40,15 +40,47 @@ func TestWebshellExecRequiresConnectionAccessWhenConnectionIDProvided(t *testing
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebshellExecRejectsAdHocURLWithoutConnectionID(t *testing.T) {
|
||||
func TestWebshellExecAllowsAdHocURLWithoutConnectionID(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
_, user, _, _ := setupWebshellRBACTest(t)
|
||||
handler := NewWebShellHandler(zap.NewNop(), nil)
|
||||
// Ad-hoc probe (connectivity test before save) must not be rejected as "无权访问".
|
||||
// The target URL will fail to connect; we only assert auth allows the request through.
|
||||
w := performWebshellJSON(user, http.MethodPost, "/api/webshell/exec", map[string]interface{}{
|
||||
"url": "http://127.0.0.1/admin", "command": "id",
|
||||
"url": "http://127.0.0.1:1/admin", "command": "id",
|
||||
}, handler.Exec)
|
||||
if w.Code == http.StatusForbidden {
|
||||
t.Fatalf("ad-hoc URL status = %d, want non-403: %s", w.Code, w.Body.String())
|
||||
}
|
||||
var resp ExecResponse
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
||||
t.Fatalf("decode response: %v body=%s", err, w.Body.String())
|
||||
}
|
||||
if resp.OK {
|
||||
t.Fatalf("expected connection failure for closed port, got ok=true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWebshellExecRejectsAdHocWithoutWritePermission(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
user := &database.RBACUser{ID: "u_ro", Username: "readonly"}
|
||||
handler := NewWebShellHandler(zap.NewNop(), nil)
|
||||
payload, _ := json.Marshal(map[string]interface{}{
|
||||
"url": "http://127.0.0.1/admin", "command": "id",
|
||||
})
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = httptest.NewRequest(http.MethodPost, "/api/webshell/exec", bytes.NewReader(payload))
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
c.Set(security.ContextSessionKey, security.Session{
|
||||
UserID: user.ID,
|
||||
Username: user.Username,
|
||||
Permissions: map[string]bool{"webshell:read": true},
|
||||
Scope: database.RBACScopeAssigned,
|
||||
})
|
||||
handler.Exec(c)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Fatalf("ad-hoc URL status = %d, want %d: %s", w.Code, http.StatusForbidden, w.Body.String())
|
||||
t.Fatalf("status = %d, want %d: %s", w.Code, http.StatusForbidden, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user