Advertisement
Guest User

Untitled

a guest
Jan 7th, 2018
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.73 KB | None | 0 0
  1. description = [[
  2. Check for vulnerabilities:
  3. * MS08-067, a Windows RPC vulnerability
  4. * Conficker, an infection by the Conficker worm
  5. * Unnamed regsvc DoS, a denial-of-service vulnerability I accidentically found in Windows 2000
  6.  
  7. WARNING: These checks are dangerous, and are very likely to bring down a server.
  8. These should not be run in a production environment unless you (and, more importantly,
  9. the business) understand the risks!
  10.  
  11. As a system administrator, performing these kinds of checks is crucial, because
  12. a lot more damage can be done by a worm or a hacker using this vulnerability than
  13. by a scanner. Penetration testers, on the other hand, might not want to use this
  14. script -- crashing services is not generally a good way of sneaking through a
  15. network.
  16.  
  17. If you set the script parameter 'unsafe', then scripts will run that are almost
  18. (or totally) guaranteed to crash a vulnerable system; do NOT specify <code>unsafe</code>
  19. in a production environment! And that isn't to say that non-unsafe scripts will
  20. not crash a system, they're just less likely to.
  21.  
  22. If you set the script parameter 'safe', then script will run that rarely or never
  23. crash a vulnerable system. No promises, though.
  24.  
  25. MS08-067 -- Checks if a host is vulnerable to MS08-067, a Windows RPC vulnerability that
  26. can allow remote code execution. Checking for MS08-067 is very dangerous, as the check
  27. is likely to crash systems. On a fairly wide scan conducted by Brandon Enright, we determined
  28. that on average, a vulnerable system is more likely to crash than to survive
  29. the check. Out of 82 vulnerable systems, 52 crashed.
  30.  
  31. At the same time, MS08-067 is extremely critical to fix. Metasploit has a working and
  32. stable exploit for it, and any system vulnerable can very easily be compromised.
  33.  
  34. Conficker -- Checks if a host is infected with a known Conficker strain. This check
  35. is based on the simple conficker scanner found on this page:
  36. http://iv.cs.uni-bonn.de/wg/cs/applications/containing-conficker
  37. Thanks to the folks who wrote that scanner!
  38.  
  39. regsvc DoS -- Checks if a host is vulnerable to a crash in regsvc, caused
  40. by a null pointer dereference. I inadvertently discovered this crash while working
  41. on <code>smb-enum-sessions</code>, and discovered that it was repeatable. It's been
  42. reported to Microsoft (case #MSRC8742).
  43.  
  44. This check WILL crash the service, if it's vulnerable, and requires a guest account
  45. or higher to work. It is considered <code>unsafe</code>.
  46.  
  47. (Note: if you have other SMB/MSRPC vulnerability checks you'd like to see added, and
  48. you can show me a tool with a license that is compatible with Nmap's, post a request
  49. on the Nmap-dev mailing list and I'll add it to my list [Ron Bowes]).
  50. ]]
  51. ---
  52. --@usage
  53. -- nmap --script smb-check-vulns.nse -p445 <host>
  54. -- sudo nmap -sU -sS --script smb-check-vulns.nse -p U:137,T:139 <host>
  55. --
  56. --@output
  57. -- Host script results:
  58. -- | smb-check-vulns:
  59. -- | MS08-067: FIXED
  60. -- | Conficker: Likely INFECTED
  61. -- |_ regsvc DoS: VULNERABLE
  62. --
  63. -- @args unsafe If set, this script will run checks that, if the system isn't
  64. -- patched, are basically guaranteed to crash something. Remember that
  65. -- non-unsafe checks aren't necessarily safe either)
  66. -- @args safe If set, this script will only run checks that are known (or at
  67. -- least suspected) to be safe.
  68. -----------------------------------------------------------------------
  69.  
  70. author = "Ron Bowes"
  71. copyright = "Ron Bowes"
  72. license = "Same as Nmap--See http://nmap.org/book/man-legal.html"
  73. categories = {"intrusive"}
  74. -- Set the runlevel to >2 so this runs last (so if it DOES crash something, it doesn't
  75. -- till other scans have had a chance to run)
  76. runlevel = 2
  77.  
  78. require 'msrpc'
  79. require 'smb'
  80. require 'stdnse'
  81.  
  82. hostrule = function(host)
  83. return smb.get_port(host) ~= nil
  84. end
  85.  
  86. local VULNERABLE = 1
  87. local PATCHED = 2
  88. local UNKNOWN = 3
  89. local NOTRUN = 4
  90. local INFECTED = 5
  91. local INFECTED2 = 6
  92. local CLEAN = 7
  93.  
  94. ---Check if the server is patched for MS08-067. This is done by calling NetPathCompare with an
  95. -- illegal string. If the string is accepted, then the server is vulnerable; if it's rejected, then
  96. -- you're safe (for now).
  97. --
  98. -- Based on a packet cap of this script, thanks go out to the author:
  99. -- http://labs.portcullis.co.uk/download/ms08-067_check.py
  100. --
  101. -- If there's a licensing issue, please let me (Ron Bowes) know so I can
  102. --
  103. -- NOTE: This CAN crash stuff (ie, crash svchost and force a reboot), so beware! In about 20
  104. -- tests I did, it crashed once. This is not a guarantee.
  105. --
  106. --@param host The host object.
  107. --@return (status, result) If status is false, result is an error code; otherwise, result is either
  108. -- <code>VULNERABLE</code> for vulnerable, <code>PATCHED</code> for not vulnerable,
  109. -- <code>UNKNOWN</code> if there was an error (likely vulnerable), <code>NOTRUN</code>
  110. -- if this check was disabled, and <code>INFECTED</code> if it was patched by Conficker.
  111. function check_ms08_067(host)
  112. if(nmap.registry.args.safe ~= nil) then
  113. return true, NOTRUN
  114. end
  115. local status, smbstate
  116. local bind_result, netpathcompare_result
  117.  
  118. -- Create the SMB session
  119. status, smbstate = msrpc.start_smb(host, "\\\\BROWSER")
  120. if(status == false) then
  121. return false, smbstate
  122. end
  123.  
  124. -- Bind to SRVSVC service
  125. status, bind_result = msrpc.bind(smbstate, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil)
  126. if(status == false) then
  127. msrpc.stop_smb(smbstate)
  128. return false, bind_result
  129. end
  130.  
  131. -- Call netpathcanonicalize
  132. -- status, netpathcanonicalize_result = msrpc.srvsvc_netpathcanonicalize(smbstate, host.ip, "\\a", "\\test\\")
  133.  
  134. local path1 = "\\AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\..\\n"
  135. local path2 = "\\n"
  136. status, netpathcompare_result = msrpc.srvsvc_netpathcompare(smbstate, host.ip, path1, path2, 1, 0)
  137.  
  138. -- Stop the SMB session
  139. msrpc.stop_smb(smbstate)
  140.  
  141. if(status == false) then
  142. if(string.find(netpathcompare_result, "UNKNOWN_57") ~= nil) then
  143. return true, INFECTED
  144. elseif(string.find(netpathcompare_result, "INVALID_NAME") ~= nil) then
  145. return true, PATCHED
  146. else
  147. return true, UNKNOWN, netpathcompare_result
  148. end
  149. end
  150.  
  151.  
  152. return true, VULNERABLE
  153. end
  154.  
  155. -- Help messages for the more common errors seen by the Conficker check.
  156. CONFICKER_ERROR_HELP = {
  157. ["NT_STATUS_BAD_NETWORK_NAME"] =
  158. [[UNKNOWN; Network name not found (required service has crashed). (Error NT_STATUS_BAD_NETWORK_NAME)]],
  159. -- http://seclists.org/nmap-dev/2009/q1/0918.html "non-Windows boxes (Samba on Linux/OS X, or a printer)"
  160. -- http://www.skullsecurity.org/blog/?p=209#comment-156
  161. -- "That means either it isn’t a Windows machine, or the service is
  162. -- either crashed or not running. That may indicate a failed (or
  163. -- successful) exploit attempt, or just a locked down system.
  164. -- NT_STATUS_OBJECT_NAME_NOT_FOUND can be returned if the browser
  165. -- service is disabled. There are at least two ways that can happen:
  166. -- 1) The service itself is disabled in the services list.
  167. -- 2) The registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Browser\Parameters\MaintainServerList
  168. -- is set to Off/False/No rather than Auto or yes.
  169. -- On these systems, if you reenable the browser service, then the
  170. -- test will complete."
  171. ["NT_STATUS_OBJECT_NAME_NOT_FOUND"] =
  172. [[UNKNOWN; not Windows, or Windows with disabled browser service (CLEAN); or Windows with crashed browser service (possibly INFECTED).
  173. | If you know the remote system is Windows, try rebooting it and scanning
  174. |_ again. (Error NT_STATUS_OBJECT_NAME_NOT_FOUND)]],
  175. -- http://www.skullsecurity.org/blog/?p=209#comment-100
  176. -- "That likely means that the server has been locked down, so we
  177. -- don’t have access to the necessary pipe. Fortunately, that means
  178. -- that neither does Conficker — NT_STATUS_ACCESS_DENIED probably
  179. -- means you’re ok."
  180. ["NT_STATUS_ACCESS_DENIED"] =
  181. [[Likely CLEAN; access was denied.
  182. | If you have a login, try using --script-args=smbuser=xxx,smbpass=yyy
  183. | (replace xxx and yyy with your username and password). Also try
  184. |_ smbdomain=zzz if you know the domain. (Error NT_STATUS_ACCESS_DENIED)]],
  185. -- The cause of these two is still unknown.
  186. -- ["NT_STATUS_NOT_SUPPORTED"] =
  187. -- [[]]
  188. -- http://thatsbroken.com/?cat=5 (doesn't seem common)
  189. -- ["NT_STATUS_REQUEST_NOT_ACCEPTED"] =
  190. -- [[]]
  191. }
  192.  
  193. ---Check if the server is infected with Conficker. This can be detected by a modified MS08-067 patch,
  194. -- which rejects a different illegal string than the official patch rejects.
  195. --
  196. -- Based loosely on the Simple Conficker Scanner, found here:
  197. -- http://iv.cs.uni-bonn.de/wg/cs/applications/containing-conficker/
  198. --
  199. -- If there's a licensing issue, please let me (Ron Bowes) know so I can fix it
  200. --
  201. --@param host The host object.
  202. --@return (status, result) If status is false, result is an error code; otherwise, result is either
  203. -- <code>INFECTED</code> for infected or <code>CLEAN</code> for not infected.
  204. function check_conficker(host)
  205. local status, smbstate
  206. local bind_result, netpathcompare_result
  207.  
  208. -- Create the SMB session
  209. status, smbstate = msrpc.start_smb(host, "\\\\BROWSER", true)
  210. if(status == false) then
  211. return false, smbstate
  212. end
  213.  
  214. -- Bind to SRVSVC service
  215. status, bind_result = msrpc.bind(smbstate, msrpc.SRVSVC_UUID, msrpc.SRVSVC_VERSION, nil)
  216. if(status == false) then
  217. msrpc.stop_smb(smbstate)
  218. return false, bind_result
  219. end
  220.  
  221. -- Try checking a valid string to find Conficker.D
  222. status, netpathcanonicalize_result, error_result = msrpc.srvsvc_netpathcanonicalize(smbstate, host.ip, "\\")
  223. if(status == true and netpathcanonicalize_result['can_path'] == 0x5c45005c) then
  224. msrpc.stop_smb(smbstate)
  225. return true, INFECTED2
  226. end
  227.  
  228. -- Try checking an illegal string ("\..\") to find Conficker.C and earlier
  229. local error_result
  230. status, netpathcanonicalize_result, error_result = msrpc.srvsvc_netpathcanonicalize(smbstate, host.ip, "\\..\\")
  231.  
  232. if(status == false) then
  233. if(string.find(netpathcanonicalize_result, "INVALID_NAME")) then
  234. msrpc.stop_smb(smbstate)
  235. return true, CLEAN
  236. elseif(string.find(netpathcanonicalize_result, "UNKNOWN_57") ~= nil) then
  237. msrpc.stop_smb(smbstate)
  238. return true, INFECTED
  239. else
  240. msrpc.stop_smb(smbstate)
  241. return false, netpathcanonicalize_result
  242. end
  243. end
  244.  
  245. -- Stop the SMB session
  246. msrpc.stop_smb(smbstate)
  247.  
  248. return true, CLEAN
  249. end
  250.  
  251. ---While writing <code>smb-enum-sessions</code> I discovered a repeatable null-pointer dereference
  252. -- in regsvc. I reported it to Microsoft, but because it's a simple DoS (and barely even that, because
  253. -- the service automatically restarts), and because it's only in Windows 2000, it isn't likely that they'll
  254. -- fix it. This function checks for that crash (by crashing the process).
  255. --
  256. -- The crash occurs when the string sent to winreg_enumkey() function is null.
  257. --
  258. --@param host The host object.
  259. --@return (status, result) If status is false, result is an error code; otherwise, result is either
  260. -- <code>VULNERABLE</code> for vulnerable or <code>PATCHED</code> for not vulnerable. If the check
  261. -- was skipped, <code>NOTRUN</code> is returned.
  262. function check_winreg_Enum_crash(host)
  263. if(nmap.registry.args.safe ~= nil) then
  264. return true, NOTRUN
  265. end
  266. if(nmap.registry.args.unsafe == nil) then
  267. return true, NOTRUN
  268. end
  269.  
  270. local i, j
  271. local elements = {}
  272.  
  273. -- Create the SMB session
  274. status, smbstate = msrpc.start_smb(host, msrpc.WINREG_PATH)
  275. if(status == false) then
  276. return false, smbstate
  277. end
  278.  
  279. -- Bind to WINREG service
  280. status, bind_result = msrpc.bind(smbstate, msrpc.WINREG_UUID, msrpc.WINREG_VERSION, nil)
  281. if(status == false) then
  282. msrpc.stop_smb(smbstate)
  283. return false, bind_result
  284. end
  285.  
  286. status, openhku_result = msrpc.winreg_openhku(smbstate)
  287. if(status == false) then
  288. msrpc.stop_smb(smbstate)
  289. return false, openhku_result
  290. end
  291.  
  292. -- Loop through the keys under HKEY_USERS and grab the names
  293. status, enumkey_result = msrpc.winreg_enumkey(smbstate, openhku_result['handle'], 0, nil)
  294. msrpc.stop_smb(smbstate)
  295.  
  296. if(status == false) then
  297. return true, VULNERABLE
  298. end
  299.  
  300. return true, PATCHED
  301. end
  302.  
  303. ---Returns the appropriate text to display, if any.
  304. --
  305. --@param check The name of the check; for example, 'ms08-067'.
  306. --@param message The message to display, such as 'VULNERABLE' or 'PATCHED'.
  307. --@param description [optional] Extra details about the message. nil for a blank message.
  308. --@param minimum_verbosity The minimum verbosity level required before the message is displayed.
  309. --@param minimum_debug [optional] The minimum debug level required before the message is displayed (default: 0).
  310. --@return A string with a textual representation of the error (or empty string, if it was determined that the message shouldn't be displayed).
  311. local function get_response(check, message, description, minimum_verbosity, minimum_debug)
  312. if(minimum_debug == nil) then
  313. minimum_debug = 0
  314. end
  315.  
  316. -- Check if we have appropriate verbosity/debug
  317. if(nmap.verbosity() >= minimum_verbosity and nmap.debugging() >= minimum_debug) then
  318. if(description == nil or description == '') then
  319. return string.format("%s: %s\n", check, message)
  320. else
  321. return string.format("%s: %s (%s)\n", check, message, description)
  322. end
  323. else
  324. return ''
  325. end
  326. end
  327.  
  328. action = function(host)
  329.  
  330. local status, result, message
  331. local response = ""
  332.  
  333. -- Check for ms08-067
  334. status, result, message = check_ms08_067(host)
  335. if(status == false) then
  336. response = response .. get_response("MS08-067", "ERROR", result, 0, 1)
  337. else
  338. if(result == VULNERABLE) then
  339. response = response .. get_response("MS08-067", "VULNERABLE", nil, 0)
  340. elseif(result == UNKNOWN) then
  341. response = response .. get_response("MS08-067", "LIKELY VULNERABLE", "host stopped responding", 1) -- TODO: this isn't very accurate
  342. elseif(result == NOTRUN) then
  343. response = response .. get_response("MS08-067", "CHECK DISABLED", "remove 'safe=1' argument to run", 1)
  344. elseif(result == INFECTED) then
  345. response = response .. get_response("MS08-067", "FIXED", "likely by Conficker", 0)
  346. else
  347. response = response .. get_response("MS08-067", "FIXED", nil, 1)
  348. end
  349. end
  350.  
  351. -- Check for Conficker
  352. status, result = check_conficker(host)
  353. if(status == false) then
  354. local msg = CONFICKER_ERROR_HELP[result] or "UNKNOWN; got error " .. result
  355. response = response .. get_response("Conficker", msg, nil, 1) -- Only set verbosity for this, since it might be an error or it might be UNKNOWN
  356. else
  357. if(result == CLEAN) then
  358. response = response .. get_response("Conficker", "Likely CLEAN", nil, 1)
  359. elseif(result == INFECTED) then
  360. response = response .. get_response("Conficker", "Likely INFECTED", "by Conficker.C or lower", 0)
  361. elseif(result == INFECTED2) then
  362. response = response .. get_response("Conficker", "Likely INFECTED", "by Conficker.D or higher", 0)
  363. else
  364. response = response .. get_response("Conficker", "UNKNOWN", result, 0, 1)
  365. end
  366. end
  367.  
  368. -- Check for a winreg_Enum crash
  369. status, result = check_winreg_Enum_crash(host)
  370. if(status == false) then
  371. response = response .. get_response("regsvc DoS", "ERROR", result, 0, 1)
  372. else
  373. if(result == VULNERABLE) then
  374. response = response .. get_response("regsvc DoS", "VULNERABLE", nil, 0)
  375. elseif(result == NOTRUN) then
  376. response = response .. get_response("regsvc DoS", "CHECK DISABLED", "add '--script-args=unsafe=1' to run", 1)
  377. else
  378. response = response .. get_response("regsvc DoS", "FIXED", "add '--script-args=unsafe=1' to run", 1)
  379. end
  380. end
  381.  
  382. -- If we got a response, add a linefeed
  383. if(response ~= "") then
  384. response = " \n" .. response
  385. else
  386. response = nil
  387. end
  388.  
  389. return response
  390. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement