librex 0.0.68 → 0.0.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. checksums.yaml +15 -0
  2. data/README.markdown +1 -1
  3. data/Rakefile +18 -16
  4. data/lib/rex.rb +14 -10
  5. data/lib/rex/LICENSE +2 -2
  6. data/lib/rex/arch.rb +76 -76
  7. data/lib/rex/arch/sparc.rb +57 -58
  8. data/lib/rex/arch/x86.rb +506 -496
  9. data/lib/rex/assembly/nasm.rb +83 -84
  10. data/lib/rex/compat.rb +228 -173
  11. data/lib/rex/constants.rb +47 -37
  12. data/lib/rex/elfparsey.rb +0 -3
  13. data/lib/rex/elfparsey/elf.rb +107 -110
  14. data/lib/rex/elfparsey/elfbase.rb +244 -247
  15. data/lib/rex/elfparsey/exceptions.rb +0 -3
  16. data/lib/rex/elfscan.rb +0 -3
  17. data/lib/rex/elfscan/scanner.rb +184 -166
  18. data/lib/rex/elfscan/search.rb +35 -38
  19. data/lib/rex/encoder/alpha2.rb +1 -2
  20. data/lib/rex/encoder/alpha2/alpha_mixed.rb +52 -53
  21. data/lib/rex/encoder/alpha2/alpha_upper.rb +62 -63
  22. data/lib/rex/encoder/alpha2/generic.rb +77 -78
  23. data/lib/rex/encoder/alpha2/unicode_mixed.rb +101 -97
  24. data/lib/rex/encoder/alpha2/unicode_upper.rb +106 -107
  25. data/lib/rex/encoder/bloxor/bloxor.rb +326 -0
  26. data/lib/rex/encoder/ndr.rb +68 -68
  27. data/lib/rex/encoder/nonalpha.rb +50 -51
  28. data/lib/rex/encoder/nonupper.rb +50 -51
  29. data/lib/rex/encoder/xdr.rb +78 -78
  30. data/lib/rex/encoder/xor.rb +52 -53
  31. data/lib/rex/encoder/xor/dword.rb +1 -2
  32. data/lib/rex/encoder/xor/dword_additive.rb +1 -2
  33. data/lib/rex/encoders/xor_dword.rb +17 -18
  34. data/lib/rex/encoders/xor_dword_additive.rb +35 -36
  35. data/lib/rex/encoding/xor.rb +0 -1
  36. data/lib/rex/encoding/xor/byte.rb +3 -4
  37. data/lib/rex/encoding/xor/dword.rb +3 -4
  38. data/lib/rex/encoding/xor/dword_additive.rb +72 -73
  39. data/lib/rex/encoding/xor/exceptions.rb +2 -3
  40. data/lib/rex/encoding/xor/generic.rb +129 -130
  41. data/lib/rex/encoding/xor/qword.rb +3 -4
  42. data/lib/rex/encoding/xor/word.rb +3 -4
  43. data/lib/rex/exceptions.rb +100 -101
  44. data/lib/rex/exploitation/cmdstager.rb +3 -3
  45. data/lib/rex/exploitation/cmdstager/base.rb +170 -156
  46. data/lib/rex/exploitation/cmdstager/bourne.rb +105 -0
  47. data/lib/rex/exploitation/cmdstager/debug_asm.rb +110 -113
  48. data/lib/rex/exploitation/cmdstager/debug_write.rb +106 -109
  49. data/lib/rex/exploitation/cmdstager/echo.rb +164 -0
  50. data/lib/rex/exploitation/cmdstager/printf.rb +122 -0
  51. data/lib/rex/exploitation/cmdstager/tftp.rb +34 -27
  52. data/lib/rex/exploitation/cmdstager/vbs.rb +95 -98
  53. data/lib/rex/exploitation/egghunter.rb +359 -346
  54. data/lib/rex/exploitation/encryptjs.rb +60 -60
  55. data/lib/rex/exploitation/heaplib.rb +76 -76
  56. data/lib/rex/exploitation/js.rb +6 -0
  57. data/lib/rex/exploitation/js/detect.rb +69 -0
  58. data/lib/rex/exploitation/js/memory.rb +81 -0
  59. data/lib/rex/exploitation/js/network.rb +84 -0
  60. data/lib/rex/exploitation/js/utils.rb +33 -0
  61. data/lib/rex/exploitation/jsobfu.rb +448 -424
  62. data/lib/rex/exploitation/obfuscatejs.rb +301 -301
  63. data/lib/rex/exploitation/omelet.rb +257 -257
  64. data/lib/rex/exploitation/opcodedb.rb +699 -699
  65. data/lib/rex/exploitation/ropdb.rb +189 -0
  66. data/lib/rex/exploitation/seh.rb +68 -68
  67. data/lib/rex/file.rb +96 -49
  68. data/lib/rex/image_source.rb +0 -3
  69. data/lib/rex/image_source/disk.rb +45 -48
  70. data/lib/rex/image_source/image_source.rb +33 -36
  71. data/lib/rex/image_source/memory.rb +17 -20
  72. data/lib/rex/io/bidirectional_pipe.rb +118 -115
  73. data/lib/rex/io/datagram_abstraction.rb +13 -14
  74. data/lib/rex/io/ring_buffer.rb +273 -273
  75. data/lib/rex/io/stream.rb +284 -284
  76. data/lib/rex/io/stream_abstraction.rb +183 -181
  77. data/lib/rex/io/stream_server.rb +193 -193
  78. data/lib/rex/job_container.rb +167 -167
  79. data/lib/rex/logging.rb +0 -1
  80. data/lib/rex/logging/log_dispatcher.rb +113 -113
  81. data/lib/rex/logging/log_sink.rb +17 -17
  82. data/lib/rex/logging/sinks/flatfile.rb +36 -36
  83. data/lib/rex/logging/sinks/stderr.rb +27 -27
  84. data/lib/rex/mac_oui.rb +16572 -16571
  85. data/lib/rex/machparsey.rb +0 -1
  86. data/lib/rex/machparsey/exceptions.rb +0 -1
  87. data/lib/rex/machparsey/mach.rb +160 -161
  88. data/lib/rex/machparsey/machbase.rb +367 -368
  89. data/lib/rex/machscan.rb +0 -1
  90. data/lib/rex/machscan/scanner.rb +175 -176
  91. data/lib/rex/mime/encoding.rb +17 -0
  92. data/lib/rex/mime/header.rb +58 -58
  93. data/lib/rex/mime/message.rb +140 -137
  94. data/lib/rex/mime/part.rb +41 -12
  95. data/lib/rex/nop/opty2.rb +90 -90
  96. data/lib/rex/nop/opty2_tables.rb +273 -273
  97. data/lib/rex/ole.rb +0 -4
  98. data/lib/rex/ole/clsid.rb +26 -30
  99. data/lib/rex/ole/difat.rb +121 -125
  100. data/lib/rex/ole/directory.rb +205 -209
  101. data/lib/rex/ole/direntry.rb +217 -221
  102. data/lib/rex/ole/fat.rb +79 -83
  103. data/lib/rex/ole/header.rb +178 -182
  104. data/lib/rex/ole/minifat.rb +49 -53
  105. data/lib/rex/ole/propset.rb +113 -117
  106. data/lib/rex/ole/samples/create_ole.rb +8 -9
  107. data/lib/rex/ole/samples/dir.rb +10 -11
  108. data/lib/rex/ole/samples/dump_stream.rb +14 -15
  109. data/lib/rex/ole/samples/ole_info.rb +5 -6
  110. data/lib/rex/ole/storage.rb +372 -376
  111. data/lib/rex/ole/stream.rb +33 -37
  112. data/lib/rex/ole/substorage.rb +20 -24
  113. data/lib/rex/ole/util.rb +137 -141
  114. data/lib/rex/parser/acunetix_nokogiri.rb +398 -398
  115. data/lib/rex/parser/apple_backup_manifestdb.rb +116 -116
  116. data/lib/rex/parser/appscan_nokogiri.rb +359 -359
  117. data/lib/rex/parser/arguments.rb +88 -88
  118. data/lib/rex/parser/burp_session_nokogiri.rb +258 -258
  119. data/lib/rex/parser/ci_nokogiri.rb +184 -184
  120. data/lib/rex/parser/foundstone_nokogiri.rb +334 -333
  121. data/lib/rex/parser/fusionvm_nokogiri.rb +94 -94
  122. data/lib/rex/parser/ini.rb +167 -167
  123. data/lib/rex/parser/ip360_aspl_xml.rb +84 -84
  124. data/lib/rex/parser/ip360_xml.rb +77 -77
  125. data/lib/rex/parser/mbsa_nokogiri.rb +224 -224
  126. data/lib/rex/parser/nessus_xml.rb +100 -100
  127. data/lib/rex/parser/netsparker_xml.rb +89 -75
  128. data/lib/rex/parser/nexpose_raw_nokogiri.rb +677 -677
  129. data/lib/rex/parser/nexpose_simple_nokogiri.rb +322 -322
  130. data/lib/rex/parser/nexpose_xml.rb +105 -105
  131. data/lib/rex/parser/nmap_nokogiri.rb +386 -386
  132. data/lib/rex/parser/nmap_xml.rb +116 -116
  133. data/lib/rex/parser/nokogiri_doc_mixin.rb +223 -221
  134. data/lib/rex/parser/openvas_nokogiri.rb +162 -162
  135. data/lib/rex/parser/outpost24_nokogiri.rb +239 -0
  136. data/lib/rex/parser/retina_xml.rb +90 -90
  137. data/lib/rex/parser/unattend.rb +171 -0
  138. data/lib/rex/parser/wapiti_nokogiri.rb +89 -89
  139. data/lib/rex/payloads/win32/common.rb +14 -14
  140. data/lib/rex/payloads/win32/kernel.rb +36 -36
  141. data/lib/rex/payloads/win32/kernel/common.rb +32 -32
  142. data/lib/rex/payloads/win32/kernel/recovery.rb +27 -27
  143. data/lib/rex/payloads/win32/kernel/stager.rb +170 -170
  144. data/lib/rex/peparsey.rb +0 -3
  145. data/lib/rex/peparsey/exceptions.rb +0 -3
  146. data/lib/rex/peparsey/pe.rb +196 -199
  147. data/lib/rex/peparsey/pe_memdump.rb +35 -38
  148. data/lib/rex/peparsey/pebase.rb +1633 -1652
  149. data/lib/rex/peparsey/section.rb +115 -124
  150. data/lib/rex/pescan.rb +0 -3
  151. data/lib/rex/pescan/analyze.rb +351 -351
  152. data/lib/rex/pescan/scanner.rb +182 -182
  153. data/lib/rex/pescan/search.rb +59 -59
  154. data/lib/rex/platforms/windows.rb +37 -37
  155. data/lib/rex/poly.rb +111 -110
  156. data/lib/rex/poly/block.rb +419 -417
  157. data/lib/rex/poly/machine.rb +12 -0
  158. data/lib/rex/poly/machine/machine.rb +829 -0
  159. data/lib/rex/poly/machine/x86.rb +508 -0
  160. data/lib/rex/poly/register.rb +70 -70
  161. data/lib/rex/poly/register/x86.rb +22 -22
  162. data/lib/rex/post.rb +0 -1
  163. data/lib/rex/post/dir.rb +35 -36
  164. data/lib/rex/post/file.rb +140 -141
  165. data/lib/rex/post/file_stat.rb +198 -199
  166. data/lib/rex/post/io.rb +167 -168
  167. data/lib/rex/post/meterpreter.rb +1 -1
  168. data/lib/rex/post/meterpreter/channel.rb +389 -390
  169. data/lib/rex/post/meterpreter/channel_container.rb +33 -34
  170. data/lib/rex/post/meterpreter/channels/pool.rb +129 -130
  171. data/lib/rex/post/meterpreter/channels/pools/file.rb +35 -36
  172. data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +72 -73
  173. data/lib/rex/post/meterpreter/channels/stream.rb +62 -63
  174. data/lib/rex/post/meterpreter/client.rb +442 -436
  175. data/lib/rex/post/meterpreter/client_core.rb +326 -310
  176. data/lib/rex/post/meterpreter/dependencies.rb +0 -1
  177. data/lib/rex/post/meterpreter/extension.rb +12 -13
  178. data/lib/rex/post/meterpreter/extensions/espia/espia.rb +35 -36
  179. data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +71 -0
  180. data/lib/rex/post/meterpreter/extensions/extapi/clipboard/clipboard.rb +169 -0
  181. data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +45 -0
  182. data/lib/rex/post/meterpreter/extensions/extapi/service/service.rb +104 -0
  183. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +77 -0
  184. data/lib/rex/post/meterpreter/extensions/extapi/window/window.rb +56 -0
  185. data/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb +75 -0
  186. data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +70 -71
  187. data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +361 -0
  188. data/lib/rex/post/meterpreter/extensions/kiwi/tlv.rb +76 -0
  189. data/lib/rex/post/meterpreter/extensions/lanattacks/dhcp/dhcp.rb +78 -0
  190. data/lib/rex/post/meterpreter/extensions/lanattacks/lanattacks.rb +22 -78
  191. data/lib/rex/post/meterpreter/extensions/lanattacks/tftp/tftp.rb +49 -0
  192. data/lib/rex/post/meterpreter/extensions/lanattacks/tlv.rb +4 -4
  193. data/lib/rex/post/meterpreter/extensions/mimikatz/mimikatz.rb +128 -0
  194. data/lib/rex/post/meterpreter/extensions/mimikatz/tlv.rb +16 -0
  195. data/lib/rex/post/meterpreter/extensions/networkpug/networkpug.rb +38 -39
  196. data/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb +1 -1
  197. data/lib/rex/post/meterpreter/extensions/priv/fs.rb +95 -96
  198. data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +39 -40
  199. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +80 -85
  200. data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +94 -95
  201. data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +207 -147
  202. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +258 -259
  203. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +366 -301
  204. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +72 -73
  205. data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +24 -25
  206. data/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb +59 -0
  207. data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +227 -149
  208. data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +107 -108
  209. data/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb +97 -0
  210. data/lib/rex/post/meterpreter/extensions/stdapi/net/resolve.rb +106 -0
  211. data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +41 -42
  212. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +102 -101
  213. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +151 -152
  214. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +142 -142
  215. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +185 -185
  216. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +38118 -38117
  217. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +7 -7
  218. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +2086 -2084
  219. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_crypt32.rb +15 -15
  220. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_iphlpapi.rb +80 -80
  221. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3835 -3833
  222. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +84 -28
  223. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ntdll.rb +151 -137
  224. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_shell32.rb +15 -6
  225. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb +3155 -3155
  226. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_version.rb +41 -0
  227. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wlanapi.rb +70 -70
  228. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wldap32.rb +128 -0
  229. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb +596 -596
  230. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +310 -301
  231. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +71 -61
  232. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +100 -100
  233. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb +14 -14
  234. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb +488 -488
  235. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +273 -264
  236. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/platform_util.rb +5 -5
  237. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +240 -238
  238. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb +17 -15
  239. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb +61 -61
  240. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +654 -635
  241. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +49 -49
  242. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +103 -102
  243. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +98 -68
  244. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +165 -166
  245. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +16 -17
  246. data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +34 -36
  247. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +363 -364
  248. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +102 -103
  249. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +28 -29
  250. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +303 -304
  251. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +113 -114
  252. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +260 -261
  253. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +165 -166
  254. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +69 -70
  255. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +160 -161
  256. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +143 -144
  257. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +29 -12
  258. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +230 -231
  259. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +181 -44
  260. data/lib/rex/post/meterpreter/inbound_packet_handler.rb +12 -13
  261. data/lib/rex/post/meterpreter/object_aliases.rb +56 -57
  262. data/lib/rex/post/meterpreter/packet.rb +591 -592
  263. data/lib/rex/post/meterpreter/packet_dispatcher.rb +506 -496
  264. data/lib/rex/post/meterpreter/packet_parser.rb +72 -73
  265. data/lib/rex/post/meterpreter/packet_response_waiter.rb +56 -57
  266. data/lib/rex/post/meterpreter/ui/console.rb +112 -112
  267. data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +53 -53
  268. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +911 -854
  269. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +86 -86
  270. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb +65 -0
  271. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +198 -0
  272. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard.rb +444 -0
  273. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb +199 -0
  274. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb +118 -0
  275. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb +108 -0
  276. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +220 -220
  277. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +509 -0
  278. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks.rb +60 -0
  279. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +254 -0
  280. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/tftp.rb +159 -0
  281. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +182 -0
  282. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +173 -173
  283. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +40 -40
  284. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +75 -77
  285. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +30 -30
  286. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +105 -105
  287. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +182 -182
  288. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +37 -37
  289. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +504 -482
  290. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +401 -330
  291. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +883 -581
  292. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +296 -299
  293. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +320 -153
  294. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +78 -78
  295. data/lib/rex/post/permission.rb +0 -1
  296. data/lib/rex/post/process.rb +39 -40
  297. data/lib/rex/post/thread.rb +41 -42
  298. data/lib/rex/post/ui.rb +35 -36
  299. data/lib/rex/proto/addp.rb +218 -0
  300. data/lib/rex/proto/dcerpc/client.rb +344 -344
  301. data/lib/rex/proto/dcerpc/exceptions.rb +128 -128
  302. data/lib/rex/proto/dcerpc/handle.rb +32 -32
  303. data/lib/rex/proto/dcerpc/ndr.rb +56 -56
  304. data/lib/rex/proto/dcerpc/packet.rb +249 -245
  305. data/lib/rex/proto/dcerpc/response.rb +170 -170
  306. data/lib/rex/proto/dcerpc/uuid.rb +65 -65
  307. data/lib/rex/proto/dcerpc/wdscp.rb +3 -0
  308. data/lib/rex/proto/dcerpc/wdscp/constants.rb +89 -0
  309. data/lib/rex/proto/dcerpc/wdscp/packet.rb +94 -0
  310. data/lib/rex/proto/dhcp.rb +0 -1
  311. data/lib/rex/proto/dhcp/constants.rb +0 -1
  312. data/lib/rex/proto/dhcp/server.rb +303 -304
  313. data/lib/rex/proto/drda/constants.rb +1 -1
  314. data/lib/rex/proto/drda/packet.rb +186 -186
  315. data/lib/rex/proto/drda/utils.rb +104 -104
  316. data/lib/rex/proto/http.rb +1 -0
  317. data/lib/rex/proto/http/client.rb +692 -820
  318. data/lib/rex/proto/http/client_request.rb +472 -0
  319. data/lib/rex/proto/http/handler.rb +25 -25
  320. data/lib/rex/proto/http/handler/erb.rb +104 -104
  321. data/lib/rex/proto/http/handler/proc.rb +37 -37
  322. data/lib/rex/proto/http/header.rb +149 -149
  323. data/lib/rex/proto/http/packet.rb +388 -382
  324. data/lib/rex/proto/http/request.rb +332 -335
  325. data/lib/rex/proto/http/response.rb +132 -72
  326. data/lib/rex/proto/http/server.rb +348 -338
  327. data/lib/rex/proto/iax2/call.rb +310 -310
  328. data/lib/rex/proto/iax2/client.rb +197 -197
  329. data/lib/rex/proto/iax2/codecs/alaw.rb +4 -4
  330. data/lib/rex/proto/iax2/codecs/mulaw.rb +4 -4
  331. data/lib/rex/proto/ipmi.rb +57 -0
  332. data/lib/rex/proto/ipmi/channel_auth_reply.rb +88 -0
  333. data/lib/rex/proto/ipmi/open_session_reply.rb +35 -0
  334. data/lib/rex/proto/ipmi/rakp2.rb +35 -0
  335. data/lib/rex/proto/ipmi/utils.rb +125 -0
  336. data/lib/rex/proto/natpmp.rb +1 -5
  337. data/lib/rex/proto/natpmp/constants.rb +4 -4
  338. data/lib/rex/proto/natpmp/packet.rb +25 -25
  339. data/lib/rex/proto/ntlm/base.rb +271 -271
  340. data/lib/rex/proto/ntlm/constants.rb +61 -61
  341. data/lib/rex/proto/ntlm/crypt.rb +348 -352
  342. data/lib/rex/proto/ntlm/exceptions.rb +3 -3
  343. data/lib/rex/proto/ntlm/message.rb +468 -471
  344. data/lib/rex/proto/ntlm/utils.rb +746 -746
  345. data/lib/rex/proto/pjl.rb +30 -0
  346. data/lib/rex/proto/pjl/client.rb +162 -0
  347. data/lib/rex/proto/proxy/socks4a.rb +440 -440
  348. data/lib/rex/proto/rfb.rb +1 -8
  349. data/lib/rex/proto/rfb/cipher.rb +46 -49
  350. data/lib/rex/proto/rfb/client.rb +179 -182
  351. data/lib/rex/proto/rfb/constants.rb +18 -21
  352. data/lib/rex/proto/smb/client.rb +1954 -1843
  353. data/lib/rex/proto/smb/constants.rb +533 -516
  354. data/lib/rex/proto/smb/crypt.rb +21 -21
  355. data/lib/rex/proto/smb/evasions.rb +43 -43
  356. data/lib/rex/proto/smb/exceptions.rb +791 -791
  357. data/lib/rex/proto/smb/simpleclient.rb +142 -286
  358. data/lib/rex/proto/smb/simpleclient/open_file.rb +106 -0
  359. data/lib/rex/proto/smb/simpleclient/open_pipe.rb +57 -0
  360. data/lib/rex/proto/smb/utils.rb +81 -81
  361. data/lib/rex/proto/sunrpc/client.rb +158 -158
  362. data/lib/rex/proto/tftp.rb +0 -1
  363. data/lib/rex/proto/tftp/client.rb +289 -289
  364. data/lib/rex/proto/tftp/constants.rb +9 -10
  365. data/lib/rex/proto/tftp/server.rb +466 -467
  366. data/lib/rex/random_identifier_generator.rb +176 -0
  367. data/lib/rex/registry.rb +1 -1
  368. data/lib/rex/registry/hive.rb +88 -88
  369. data/lib/rex/registry/lfkey.rb +25 -25
  370. data/lib/rex/registry/nodekey.rb +30 -30
  371. data/lib/rex/registry/regf.rb +10 -10
  372. data/lib/rex/registry/valuekey.rb +43 -43
  373. data/lib/rex/registry/valuelist.rb +13 -13
  374. data/lib/rex/ropbuilder/rop.rb +254 -253
  375. data/lib/rex/script.rb +21 -22
  376. data/lib/rex/script/base.rb +51 -50
  377. data/lib/rex/script/meterpreter.rb +2 -2
  378. data/lib/rex/service.rb +24 -24
  379. data/lib/rex/service_manager.rb +132 -132
  380. data/lib/rex/services/local_relay.rb +398 -398
  381. data/lib/rex/socket.rb +758 -763
  382. data/lib/rex/socket/comm.rb +95 -95
  383. data/lib/rex/socket/comm/local.rb +507 -440
  384. data/lib/rex/socket/ip.rb +118 -118
  385. data/lib/rex/socket/parameters.rb +351 -350
  386. data/lib/rex/socket/range_walker.rb +445 -368
  387. data/lib/rex/socket/ssl_tcp.rb +323 -317
  388. data/lib/rex/socket/ssl_tcp_server.rb +173 -158
  389. data/lib/rex/socket/subnet_walker.rb +48 -48
  390. data/lib/rex/socket/switch_board.rb +259 -259
  391. data/lib/rex/socket/tcp.rb +58 -56
  392. data/lib/rex/socket/tcp_server.rb +42 -42
  393. data/lib/rex/socket/udp.rb +152 -152
  394. data/lib/rex/sslscan/result.rb +200 -0
  395. data/lib/rex/sslscan/scanner.rb +205 -0
  396. data/lib/rex/struct2.rb +0 -1
  397. data/lib/rex/struct2/c_struct.rb +162 -163
  398. data/lib/rex/struct2/c_struct_template.rb +21 -22
  399. data/lib/rex/struct2/constant.rb +6 -7
  400. data/lib/rex/struct2/element.rb +30 -31
  401. data/lib/rex/struct2/generic.rb +60 -61
  402. data/lib/rex/struct2/restraint.rb +40 -41
  403. data/lib/rex/struct2/s_string.rb +60 -61
  404. data/lib/rex/struct2/s_struct.rb +97 -98
  405. data/lib/rex/sync.rb +0 -1
  406. data/lib/rex/sync/event.rb +62 -72
  407. data/lib/rex/sync/read_write_lock.rb +149 -149
  408. data/lib/rex/sync/ref.rb +42 -42
  409. data/lib/rex/sync/thread_safe.rb +59 -59
  410. data/lib/rex/text.rb +1803 -1315
  411. data/lib/rex/thread_factory.rb +25 -25
  412. data/lib/rex/time.rb +44 -44
  413. data/lib/rex/transformer.rb +91 -91
  414. data/lib/rex/ui/interactive.rb +265 -265
  415. data/lib/rex/ui/output.rb +66 -60
  416. data/lib/rex/ui/progress_tracker.rb +79 -79
  417. data/lib/rex/ui/subscriber.rb +144 -134
  418. data/lib/rex/ui/text/color.rb +76 -76
  419. data/lib/rex/ui/text/dispatcher_shell.rb +512 -505
  420. data/lib/rex/ui/text/input.rb +96 -96
  421. data/lib/rex/ui/text/input/buffer.rb +58 -58
  422. data/lib/rex/ui/text/input/readline.rb +114 -114
  423. data/lib/rex/ui/text/input/socket.rb +77 -77
  424. data/lib/rex/ui/text/input/stdio.rb +24 -24
  425. data/lib/rex/ui/text/irb_shell.rb +45 -41
  426. data/lib/rex/ui/text/output.rb +64 -60
  427. data/lib/rex/ui/text/output/buffer.rb +42 -42
  428. data/lib/rex/ui/text/output/buffer/stdout.rb +25 -0
  429. data/lib/rex/ui/text/output/file.rb +24 -24
  430. data/lib/rex/ui/text/output/socket.rb +24 -24
  431. data/lib/rex/ui/text/output/stdio.rb +29 -29
  432. data/lib/rex/ui/text/output/tee.rb +36 -36
  433. data/lib/rex/ui/text/progress_tracker.rb +37 -37
  434. data/lib/rex/ui/text/shell.rb +371 -361
  435. data/lib/rex/ui/text/table.rb +320 -284
  436. data/lib/rex/zip.rb +0 -1
  437. data/lib/rex/zip/archive.rb +115 -94
  438. data/lib/rex/zip/blocks.rb +101 -100
  439. data/lib/rex/zip/entry.rb +108 -99
  440. data/lib/rex/zip/jar.rb +261 -206
  441. data/lib/rex/zip/samples/comment.rb +1 -2
  442. data/lib/rex/zip/samples/mkwar.rb +12 -13
  443. data/lib/rex/zip/samples/mkzip.rb +1 -2
  444. data/lib/rex/zip/samples/recursive.rb +29 -30
  445. metadata +424 -446
  446. data/lib/rex/arch/sparc.rb.ut.rb +0 -19
  447. data/lib/rex/arch/x86.rb.ut.rb +0 -94
  448. data/lib/rex/assembly/nasm.rb.ut.rb +0 -23
  449. data/lib/rex/encoder/ndr.rb.ut.rb +0 -45
  450. data/lib/rex/encoder/xdr.rb.ut.rb +0 -30
  451. data/lib/rex/encoders/xor_dword_additive.rb.ut.rb +0 -13
  452. data/lib/rex/encoding/xor.rb.ts.rb +0 -15
  453. data/lib/rex/encoding/xor/byte.rb.ut.rb +0 -22
  454. data/lib/rex/encoding/xor/dword.rb.ut.rb +0 -16
  455. data/lib/rex/encoding/xor/dword_additive.rb.ut.rb +0 -16
  456. data/lib/rex/encoding/xor/generic.rb.ut.rb +0 -121
  457. data/lib/rex/encoding/xor/word.rb.ut.rb +0 -14
  458. data/lib/rex/exceptions.rb.ut.rb +0 -45
  459. data/lib/rex/exploitation/egghunter.rb.ut.rb +0 -28
  460. data/lib/rex/exploitation/javascriptosdetect.js +0 -1014
  461. data/lib/rex/exploitation/javascriptosdetect.rb +0 -43
  462. data/lib/rex/exploitation/omelet.rb.ut.rb +0 -27
  463. data/lib/rex/exploitation/opcodedb.rb.ut.rb +0 -280
  464. data/lib/rex/exploitation/seh.rb.ut.rb +0 -20
  465. data/lib/rex/file.rb.ut.rb +0 -17
  466. data/lib/rex/io/ring_buffer.rb.ut.rb +0 -135
  467. data/lib/rex/nop/opty2.rb.ut.rb +0 -24
  468. data/lib/rex/parser/arguments.rb.ut.rb +0 -68
  469. data/lib/rex/parser/ini.rb.ut.rb +0 -30
  470. data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +0 -18
  471. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +0 -39
  472. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb.ut.rb +0 -37
  473. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb.ut.rb +0 -52
  474. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb +0 -43
  475. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +0 -128
  476. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb.ut.rb +0 -64
  477. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/platform_util.rb.ut.rb +0 -29
  478. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb.ut.rb +0 -155
  479. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb.ut.rb +0 -128
  480. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb.ut.rb +0 -124
  481. data/lib/rex/proto.rb.ts.rb +0 -9
  482. data/lib/rex/proto/dcerpc.rb.ts.rb +0 -10
  483. data/lib/rex/proto/dcerpc/client.rb.ut.rb +0 -492
  484. data/lib/rex/proto/dcerpc/handle.rb.ut.rb +0 -86
  485. data/lib/rex/proto/dcerpc/ndr.rb.ut.rb +0 -42
  486. data/lib/rex/proto/dcerpc/packet.rb.ut.rb +0 -57
  487. data/lib/rex/proto/dcerpc/response.rb.ut.rb +0 -16
  488. data/lib/rex/proto/dcerpc/uuid.rb.ut.rb +0 -47
  489. data/lib/rex/proto/drda.rb.ts.rb +0 -18
  490. data/lib/rex/proto/drda/constants.rb.ut.rb +0 -24
  491. data/lib/rex/proto/drda/packet.rb.ut.rb +0 -110
  492. data/lib/rex/proto/drda/utils.rb.ut.rb +0 -85
  493. data/lib/rex/proto/http.rb.ts.rb +0 -13
  494. data/lib/rex/proto/http/client.rb.ut.rb +0 -96
  495. data/lib/rex/proto/http/handler/erb.rb.ut.rb +0 -22
  496. data/lib/rex/proto/http/handler/erb.rb.ut.rb.rhtml +0 -1
  497. data/lib/rex/proto/http/handler/proc.rb.ut.rb +0 -25
  498. data/lib/rex/proto/http/header.rb.ut.rb +0 -47
  499. data/lib/rex/proto/http/packet.rb.ut.rb +0 -166
  500. data/lib/rex/proto/http/request.rb.ut.rb +0 -215
  501. data/lib/rex/proto/http/response.rb.ut.rb +0 -150
  502. data/lib/rex/proto/http/server.rb.ut.rb +0 -80
  503. data/lib/rex/proto/ntlm.rb.ut.rb +0 -181
  504. data/lib/rex/proto/rfb.rb.ut.rb +0 -40
  505. data/lib/rex/proto/smb.rb.ts.rb +0 -9
  506. data/lib/rex/proto/smb/client.rb.ut.rb +0 -224
  507. data/lib/rex/proto/smb/constants.rb.ut.rb +0 -19
  508. data/lib/rex/proto/smb/simpleclient.rb.ut.rb +0 -129
  509. data/lib/rex/proto/smb/utils.rb.ut.rb +0 -21
  510. data/lib/rex/proto/tftp/server.rb.ut.rb +0 -29
  511. data/lib/rex/service_manager.rb.ut.rb +0 -33
  512. data/lib/rex/socket.rb.ut.rb +0 -108
  513. data/lib/rex/socket/comm/local.rb.ut.rb +0 -76
  514. data/lib/rex/socket/parameters.rb.ut.rb +0 -52
  515. data/lib/rex/socket/range_walker.rb.ut.rb +0 -56
  516. data/lib/rex/socket/ssl_tcp.rb.ut.rb +0 -40
  517. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +0 -62
  518. data/lib/rex/socket/subnet_walker.rb.ut.rb +0 -29
  519. data/lib/rex/socket/switch_board.rb.ut.rb +0 -53
  520. data/lib/rex/socket/tcp.rb.ut.rb +0 -65
  521. data/lib/rex/socket/tcp_server.rb.ut.rb +0 -45
  522. data/lib/rex/socket/udp.rb.ut.rb +0 -45
  523. data/lib/rex/test.rb +0 -36
  524. data/lib/rex/text.rb.ut.rb +0 -193
  525. data/lib/rex/transformer.rb.ut.rb +0 -39
  526. data/lib/rex/ui/text/color.rb.ut.rb +0 -19
  527. data/lib/rex/ui/text/progress_tracker.rb.ut.rb +0 -35
  528. data/lib/rex/ui/text/table.rb.ut.rb +0 -56
@@ -8,112 +8,112 @@ module Parser
8
8
 
9
9
  class NessusXMLStreamParser
10
10
 
11
- attr_accessor :on_found_host
11
+ attr_accessor :on_found_host
12
12
 
13
- def initialize(&block)
14
- reset_state
15
- on_found_host = block if block
16
- end
13
+ def initialize(&block)
14
+ reset_state
15
+ on_found_host = block if block
16
+ end
17
17
 
18
- def reset_state
19
- @host = {'hname' => nil, 'addr' => nil, 'mac' => nil, 'os' => nil, 'ports' => [
20
- 'port' => {'port' => nil, 'svc_name' => nil, 'proto' => nil, 'severity' => nil,
21
- 'nasl' => nil, 'nasl_name' => nil, 'description' => nil,
22
- 'cve' => [], 'bid' => [], 'xref' => [], 'msf' => nil } ] }
23
- @state = :generic_state
24
- end
18
+ def reset_state
19
+ @host = {'hname' => nil, 'addr' => nil, 'mac' => nil, 'os' => nil, 'ports' => [
20
+ 'port' => {'port' => nil, 'svc_name' => nil, 'proto' => nil, 'severity' => nil,
21
+ 'nasl' => nil, 'nasl_name' => nil, 'description' => nil,
22
+ 'cve' => [], 'bid' => [], 'xref' => [], 'msf' => nil } ] }
23
+ @state = :generic_state
24
+ end
25
25
 
26
- def tag_start(name, attributes)
27
- case name
28
- when "tag"
29
- if attributes['name'] == "mac-address"
30
- @state = :is_mac
31
- end
32
- if attributes['name'] == "host-fqdn"
33
- @state = :is_fqdn
34
- end
35
- if attributes['name'] == "ip-addr"
36
- @state = :is_ip
37
- end
38
- if attributes['name'] == "host-ip"
39
- @state = :is_ip
40
- end
41
- if attributes['name'] == "operating-system"
42
- @state = :is_os
43
- end
44
- when "ReportHost"
45
- @host['hname'] = attributes['name']
46
- when "ReportItem"
47
- @cve = Array.new
48
- @bid = Array.new
49
- @xref = Array.new
50
- @x = Hash.new
51
- @x['nasl'] = attributes['pluginID']
52
- @x['nasl_name'] = attributes['pluginName']
53
- @x['port'] = attributes['port']
54
- @x['proto'] = attributes['protocol']
55
- @x['svc_name'] = attributes['svc_name']
56
- @x['severity'] = attributes['severity']
57
- when "description"
58
- @state = :is_desc
59
- when "cve"
60
- @state = :is_cve
61
- when "bid"
62
- @state = :is_bid
63
- when "xref"
64
- @state = :is_xref
65
- when "solution"
66
- @state = :is_solution
67
- when "metasploit_name"
68
- @state = :msf
69
- end
70
- end
26
+ def tag_start(name, attributes)
27
+ case name
28
+ when "tag"
29
+ if attributes['name'] == "mac-address"
30
+ @state = :is_mac
31
+ end
32
+ if attributes['name'] == "host-fqdn"
33
+ @state = :is_fqdn
34
+ end
35
+ if attributes['name'] == "ip-addr"
36
+ @state = :is_ip
37
+ end
38
+ if attributes['name'] == "host-ip"
39
+ @state = :is_ip
40
+ end
41
+ if attributes['name'] == "operating-system"
42
+ @state = :is_os
43
+ end
44
+ when "ReportHost"
45
+ @host['hname'] = attributes['name']
46
+ when "ReportItem"
47
+ @cve = Array.new
48
+ @bid = Array.new
49
+ @xref = Array.new
50
+ @x = Hash.new
51
+ @x['nasl'] = attributes['pluginID']
52
+ @x['nasl_name'] = attributes['pluginName']
53
+ @x['port'] = attributes['port']
54
+ @x['proto'] = attributes['protocol']
55
+ @x['svc_name'] = attributes['svc_name']
56
+ @x['severity'] = attributes['severity']
57
+ when "description"
58
+ @state = :is_desc
59
+ when "cve"
60
+ @state = :is_cve
61
+ when "bid"
62
+ @state = :is_bid
63
+ when "xref"
64
+ @state = :is_xref
65
+ when "solution"
66
+ @state = :is_solution
67
+ when "metasploit_name"
68
+ @state = :msf
69
+ end
70
+ end
71
71
 
72
- def text(str)
73
- case @state
74
- when :is_fqdn
75
- @host['hname'] = str
76
- when :is_ip
77
- @host['addr'] = str
78
- when :is_os
79
- @host['os'] = str
80
- when :is_mac
81
- @host['mac'] = str
82
- when :is_desc
83
- @x['description'] = str
84
- when :is_cve
85
- @cve.push str
86
- when :is_bid
87
- @bid.push str
88
- when :is_xref
89
- @xref.push str
90
- when :msf
91
- #p str
92
- @x['msf'] = str
93
- end
94
- end
72
+ def text(str)
73
+ case @state
74
+ when :is_fqdn
75
+ @host['hname'] = str
76
+ when :is_ip
77
+ @host['addr'] = str
78
+ when :is_os
79
+ @host['os'] = str
80
+ when :is_mac
81
+ @host['mac'] = str
82
+ when :is_desc
83
+ @x['description'] = str
84
+ when :is_cve
85
+ @cve.push str
86
+ when :is_bid
87
+ @bid.push str
88
+ when :is_xref
89
+ @xref.push str
90
+ when :msf
91
+ #p str
92
+ @x['msf'] = str
93
+ end
94
+ end
95
95
 
96
- def tag_end(name)
97
- case name
98
- when "ReportHost"
99
- on_found_host.call(@host) if on_found_host
100
- reset_state
101
- when "ReportItem"
102
- @x['cve'] = @cve
103
- @x['bid'] = @bid
104
- @x['xref'] = @xref
105
- @host['ports'].push @x
106
- end
107
- @state = :generic_state
108
- end
96
+ def tag_end(name)
97
+ case name
98
+ when "ReportHost"
99
+ on_found_host.call(@host) if on_found_host
100
+ reset_state
101
+ when "ReportItem"
102
+ @x['cve'] = @cve
103
+ @x['bid'] = @bid
104
+ @x['xref'] = @xref
105
+ @host['ports'].push @x
106
+ end
107
+ @state = :generic_state
108
+ end
109
109
 
110
- # We don't need these methods, but they're necessary to keep REXML happy
111
- #
112
- def xmldecl(version, encoding, standalone); end
113
- def cdata; end
114
- def comment(str); end
115
- def instruction(name, instruction); end
116
- def attlist; end
110
+ # We don't need these methods, but they're necessary to keep REXML happy
111
+ #
112
+ def xmldecl(version, encoding, standalone); end
113
+ def cdata; end
114
+ def comment(str); end
115
+ def instruction(name, instruction); end
116
+ def attlist; end
117
117
  end
118
118
 
119
119
  end
@@ -5,88 +5,102 @@ module Parser
5
5
 
6
6
  class NetSparkerXMLStreamParser
7
7
 
8
- attr_accessor :on_found_vuln
8
+ attr_accessor :on_found_vuln
9
9
 
10
- def initialize(on_found_vuln = nil)
11
- self.on_found_vuln = on_found_vuln if on_found_vuln
12
- reset_state
13
- end
10
+ def initialize(on_found_vuln = nil)
11
+ self.on_found_vuln = on_found_vuln if on_found_vuln
12
+ reset_state
13
+ end
14
14
 
15
- def reset_state
16
- @state = :generic_state
17
- @vuln = {'info' => []}
18
- @attr = {}
19
- end
15
+ def reset_state
16
+ @state = :generic_state
17
+ @vuln = {'info' => []}
18
+ @attr = {}
19
+ end
20
20
 
21
- def tag_start(name, attributes)
22
- @state = "in_#{name.downcase}".intern
23
- @attr = attributes
21
+ def tag_start(name, attributes)
22
+ @state = "in_#{name.downcase}".intern
23
+ @attr = attributes
24
24
 
25
- case name
26
- when "vulnerability"
27
- @vuln['confirmed'] = attributes['confirmed']
28
- end
29
- end
25
+ case name
26
+ when "vulnerability"
27
+ @vuln = { 'info' => [] }
28
+ @vuln['confirmed'] = attributes['confirmed']
29
+ end
30
+ end
30
31
 
31
- def text(str)
32
- case @state
33
- when :in_url
34
- @vuln['url'] ||= ""
35
- @vuln['url'] += str
36
- when :in_type
37
- @vuln['type'] ||= ""
38
- @vuln['type'] += str
39
- when :in_severity
40
- @vuln['severity'] ||= ""
41
- @vuln['severity'] += str
42
- when :in_vulnerableparametertype
43
- @vuln["vparam_type"] ||= ""
44
- @vuln["vparam_type"] += str
45
- when :in_vulnerableparameter
46
- @vuln["vparam_name"] ||= ""
47
- @vuln["vparam_name"] += str
48
- when :in_vulnerableparametervalue
49
- @vuln["vparam_value"] ||= ""
50
- @vuln["vparam_value"] += str
51
- when :in_rawrequest
52
- @vuln["request"] ||= ""
53
- @vuln["request"] += str
54
- when :in_rawresponse
55
- @vuln["response"] ||= ""
56
- @vuln["response"] += str
57
- when :in_info
58
- # <info name="Identified Internal Path(s)">C:\AppServ\www\test-apps\dokeos\main\inc\banner.inc.php</info>
59
- if not str.to_s.strip.empty?
60
- @vuln['info'] << [@attr['name'] || "Information", str]
61
- end
62
- when :in_netsparker
63
- when :in_target
64
- when :in_scantime
65
- when :generic_state
66
- when :in_vulnerability
67
- when :in_extrainformation
68
- else
69
- # $stderr.puts "unknown state: #{@state}"
70
- end
71
- end
32
+ def text(str)
33
+ case @state
34
+ when :in_url
35
+ @vuln['url'] ||= ""
36
+ @vuln['url'] += str
37
+ when :in_type
38
+ @vuln['type'] ||= ""
39
+ @vuln['type'] += str
40
+ when :in_severity
41
+ @vuln['severity'] ||= ""
42
+ @vuln['severity'] += str
43
+ when :in_vulnerableparametertype
44
+ @vuln["vparam_type"] ||= ""
45
+ @vuln["vparam_type"] += str
46
+ when :in_vulnerableparameter
47
+ @vuln["vparam_name"] ||= ""
48
+ @vuln["vparam_name"] += str
49
+ when :in_vulnerableparametervalue
50
+ @vuln["vparam_value"] ||= ""
51
+ @vuln["vparam_value"] += str
52
+ when :in_rawrequest
53
+ @vuln["request"] ||= ""
54
+ @vuln["request"] += str
55
+ when :in_rawresponse
56
+ @vuln["response"] ||= ""
57
+ @vuln["response"] += str
58
+ when :in_info
59
+ # <info name="Identified Internal Path(s)">C:\AppServ\www\test-apps\dokeos\main\inc\banner.inc.php</info>
60
+ if not str.to_s.strip.empty?
61
+ @vuln['info'] << [@attr['name'] || "Information", str]
62
+ end
63
+ when :in_netsparker
64
+ when :in_target
65
+ when :in_scantime
66
+ when :generic_state
67
+ when :in_vulnerability
68
+ when :in_extrainformation
69
+ else
70
+ # $stderr.puts "unknown state: #{@state}"
71
+ end
72
+ end
72
73
 
73
- def tag_end(name)
74
- case name
75
- when "vulnerability"
76
- @vuln.keys.each do |k|
77
- @vuln[k] = @vuln[k].strip if @vuln[k].kind_of?(::String)
78
- end
79
- on_found_vuln.call(@vuln) if on_found_vuln
80
- reset_state
81
- end
82
- end
74
+ def tag_end(name)
75
+ case name
76
+ when "vulnerability"
77
+ @vuln.keys.each do |k|
78
+ @vuln[k] = @vuln[k].strip if @vuln[k].kind_of?(::String)
79
+ end
80
+ on_found_vuln.call(@vuln) if on_found_vuln
81
+ reset_state
82
+ end
83
+ end
83
84
 
84
- # We don't need these methods, but they're necessary to keep REXML happy
85
- def xmldecl(version, encoding, standalone); end
86
- def cdata; end
87
- def comment(str); end
88
- def instruction(name, instruction); end
89
- def attlist; end
85
+ # We don't need these methods, but they're necessary to keep REXML happy
86
+ def xmldecl(version, encoding, standalone); end
87
+ def cdata(data)
88
+ puts "cdata for #{@state} (#{data.length})"
89
+ case @state
90
+ when :in_rawresponse
91
+ @vuln["response"] = data
92
+ when :in_rawrequest
93
+ @vuln["request"] = data
94
+ when :in_info
95
+ if not data.to_s.strip.empty?
96
+ @vuln['info'] << [@attr['name'] || "Information", data]
97
+ end
98
+ end
99
+ end
100
+
101
+ def comment(str); end
102
+ def instruction(name, instruction); end
103
+ def attlist; end
90
104
  end
91
105
  end
92
106
  end
@@ -3,683 +3,683 @@ require "rex/parser/nokogiri_doc_mixin"
3
3
  require "date"
4
4
 
5
5
  module Rex
6
- module Parser
7
-
8
- # If Nokogiri is available, define Template document class.
9
- load_nokogiri && class NexposeRawDocument < Nokogiri::XML::SAX::Document
10
-
11
- include NokogiriDocMixin
12
-
13
- attr_reader :tests
14
-
15
- NEXPOSE_HOST_DETAIL_FIELDS = %W{ nx_device_id nx_site_name nx_site_importance nx_scan_template nx_risk_score }
16
- NEXPOSE_VULN_DETAIL_FIELDS = %W{
17
- nx_scan_id
18
- nx_vulnerable_since
19
- nx_pci_compliance_status
20
- }
21
-
22
- # Triggered every time a new element is encountered. We keep state
23
- # ourselves with the @state variable, turning things on when we
24
- # get here (and turning things off when we exit in end_element()).
25
- def start_element(name=nil,attrs=[])
26
- attrs = normalize_attrs(attrs)
27
- block = @block
28
- @state[:current_tag][name] = true
29
- case name
30
- when "nodes" # There are two main sections, nodes and VulnerabilityDefinitions
31
- @tests = {}
32
- when "node"
33
- record_host(attrs)
34
- when "name"
35
- @state[:has_text] = true
36
- when "endpoint"
37
- @state.delete(:cached_service_object)
38
- record_service(attrs)
39
- when "service"
40
- record_service_info(attrs)
41
- when "fingerprint"
42
- record_service_fingerprint(attrs)
43
- when "os"
44
- record_os_fingerprint(attrs)
45
- when "test" # All the vulns tested for
46
- @state[:has_text] = true
47
- record_host_test(attrs)
48
- record_service_test(attrs)
49
- when "vulnerability"
50
- record_vuln(attrs)
51
- when "reference"
52
- @state[:has_text] = true
53
- record_reference(attrs)
54
- when "description"
55
- @state[:has_text] = true
56
- record_vuln_description(attrs)
57
- when "solution"
58
- @state[:has_text] = true
59
- record_vuln_solution(attrs)
60
- when "tag"
61
- @state[:has_text] = true
62
- when "tags"
63
- @state[:tags] = []
64
- #
65
- # These are markup tags only present within description/solutions
66
- #
67
- when "ContainerBlockElement", # Overall container, no formatting
68
- "Paragraph", # <Paragraph preformat="true">
69
- "UnorderedList", # List container (bulleted)
70
- "ListItem", # List item
71
- "URLLink" # <URLLink LinkURL="http://support.microsoft.com/kb/887429" LinkTitle="http://support.microsoft.com/kb/887429" href="http://support.microsoft.com/kb/887429">KB 887429</URLLink>
72
-
73
- record_formatted_content(name, attrs)
74
-
75
- end
76
- end
77
-
78
- # When we exit a tag, this is triggered.
79
- def end_element(name=nil)
80
- block = @block
81
- case name
82
- when "node" # Wrap it up
83
- collect_host_data
84
- host_object = report_host &block
85
- report_services(host_object)
86
- report_fingerprint(host_object)
87
- # Reset the state once we close a host
88
- @state.delete_if {|k| k.to_s !~ /^(current_tag|in_nodes)$/}
89
- @report_data = {:wspace => @args[:wspace]}
90
- when "name"
91
- collect_hostname
92
- @state[:has_text] = false
93
- @text = nil
94
- when "endpoint"
95
- collect_service_data
96
- @state.delete(:cached_service_object)
97
- when "os"
98
- collect_os_fingerprints
99
- when "test"
100
- report_test(&block)
101
- @state[:has_text] = false
102
- @text = nil
103
- when "vulnerability"
104
- collect_vuln_info
105
- report_vuln(&block)
106
- @state.delete_if {|k| k.to_s !~ /^(current_tag|in_vulndefs)$/}
107
- when "reference"
108
- @state[:has_text] = false
109
- collect_reference
110
- @text = nil
111
- when "description"
112
- @state[:has_text] = false
113
- collect_vuln_description
114
- @text = nil
115
- when "solution"
116
- @state[:has_text] = false
117
- collect_vuln_solution
118
- @text = nil
119
- when "tag"
120
- @state[:has_text] = false
121
- collect_tag
122
- @text = nil
123
- when "tags"
124
- @report_data[:vuln_tags] = @state[:tags]
125
- @state.delete(:tags)
126
- #
127
- # These are markup tags only present within description/solutions
128
- #
129
- when "ContainerBlockElement", # Overall container, no formatting
130
- "Paragraph", # <Paragraph preformat="true">
131
- "UnorderedList", # List container (bulleted)
132
- "ListItem", # List item
133
- "URLLink" # <URLLink LinkURL="http://support.microsoft.com/kb/887429" LinkTitle="http://support.microsoft.com/kb/887429" href="http://support.microsoft.com/kb/887429">KB 887429</URLLink>
134
-
135
- collect_formatted_content(name)
136
- end
137
- @state[:current_tag].delete name
138
- end
139
-
140
- def collect_reference
141
- return unless in_tag("references")
142
- return unless in_tag("vulnerability")
143
- return unless @state[:vuln]
144
- @state[:ref][:value] = @text.to_s.strip
145
- @report_data[:refs] ||= []
146
- @report_data[:refs] << @state[:ref]
147
- @state[:ref] = nil
148
- end
149
-
150
- def collect_vuln_description
151
- return unless in_tag("description")
152
- return unless in_tag("vulnerability")
153
- return unless @state[:vuln]
154
- @report_data[:vuln_description] = clean_formatted_text( @report_data[:vuln_description_stack].join.strip )
155
- end
156
-
157
- def collect_vuln_solution
158
- return unless in_tag("solution")
159
- return unless in_tag("vulnerability")
160
- return unless @state[:vuln]
161
- @report_data[:vuln_solution] = clean_formatted_text( @report_data[:vuln_solution_stack].join.strip )
162
- end
163
-
164
- def collect_tag
165
- return unless in_tag("tag")
166
- return unless in_tag("tags")
167
- return unless in_tag("vulnerability")
168
- return unless @state[:vuln]
169
- @state[:tags] ||= []
170
- @state[:tags] << @text.to_s.strip
171
- end
172
-
173
- def collect_vuln_info
174
- return unless in_tag("VulnerabilityDefinitions")
175
- return unless in_tag("vulnerability")
176
- return unless @state[:vuln]
177
- vuln = @state[:vuln]
178
- vuln[:refs] = @report_data[:refs]
179
- @report_data[:vuln] = vuln
180
- @state[:vuln] = nil
181
- @report_data[:refs] = nil
182
- end
183
-
184
- def report_vuln(&block)
185
- return unless in_tag("VulnerabilityDefinitions")
186
- return unless @report_data[:vuln]
187
- return unless @report_data[:vuln][:matches].kind_of? Array
188
-
189
- ::ActiveRecord::Base.connection_pool.with_connection {
190
-
191
- refs = normalize_references(@report_data[:vuln][:refs])
192
- refs << "NEXPOSE-#{report_data[:vuln]["id"]}"
193
- vuln_instances = @report_data[:vuln][:matches].size
194
- db.emit(:vuln, [refs.last,vuln_instances], &block) if block
195
-
196
- vuln_ids = @report_data[:vuln][:matches].map{ |v| v[0] }
197
- vdet_ids = @report_data[:vuln][:matches].map{ |v| v[1] }
198
-
199
- refs = refs.uniq.map{|x| db.find_or_create_ref(:name => x) }
200
-
201
- # Assign title and references to all vuln_ids
202
- # Mass update fails due to the join table || ::Mdm::Vuln.where(:id => vuln_ids).update_all({ :name => @report_data[:vuln]["title"], :refs => refs } )
203
- vuln_ids.each do |vid|
204
- vuln = ::Mdm::Vuln.find(vid)
205
- next unless vuln
206
- vuln.name = @report_data[:vuln]["title"]
207
-
208
- if refs.length > 0
209
- vuln.refs += refs
210
- end
211
-
212
- if vuln.changed?
213
- vuln.save!
214
- end
215
- end
216
-
217
- # Mass update vulnerability details across the database based on conditions
218
- vdet_info = { :title => @report_data[:vuln]["title"] }
219
- vdet_info[:description] = @report_data[:vuln_description] unless @report_data[:vuln_description].to_s.empty?
220
- vdet_info[:solution] = @report_data[:vuln_solution] unless @report_data[:vuln_solution].to_s.empty?
221
- vdet_info[:nx_tags] = @report_data[:vuln_tags].sort.uniq.join(", ") if ( @report_data[:vuln_tags].kind_of?(::Array) and @report_data[:vuln_tags].length > 0 )
222
- vdet_info[:nx_severity] = @report_data[:vuln]["severity"].to_f if @report_data[:vuln]["severity"]
223
- vdet_info[:nx_pci_severity] = @report_data[:vuln]["pciSeverity"].to_f if @report_data[:vuln]["pciSeverity"]
224
- vdet_info[:cvss_score] = @report_data[:vuln]["cvssScore"].to_f if @report_data[:vuln]["cvssScore"]
225
- vdet_info[:cvss_vector] = @report_data[:vuln]["cvssVector"] if @report_data[:vuln]["cvssVector"]
226
-
227
- %W{ published added modified }.each do |tf|
228
- next if not @report_data[:vuln][tf]
229
- ts = DateTime.parse(@report_data[:vuln][tf]) rescue nil
230
- next if not ts
231
- vdet_info[ "nx_#{tf}".to_sym ] = ts
232
- end
233
-
234
- ::Mdm::VulnDetail.where(:id => vdet_ids).update_all(vdet_info)
235
-
236
- @report_data[:vuln] = nil
237
-
238
- }
239
- end
240
-
241
- def record_reference(attrs)
242
- return unless in_tag("VulnerabilityDefinitions")
243
- return unless in_tag("vulnerability")
244
- @state[:ref] = attr_hash(attrs)
245
- end
246
-
247
- def record_vuln(attrs)
248
- return unless in_tag("VulnerabilityDefinitions")
249
- vuln = attr_hash(attrs)
250
- matching_tests = @tests[ vuln["id"].downcase ]
251
- return unless matching_tests
252
- return if matching_tests.empty?
253
- @state[:vuln] = vuln
254
- @state[:vuln][:matches] = matching_tests
255
- end
256
-
257
- def record_vuln_description(attrs)
258
- @report_data[:vuln_description_stack] = []
259
- end
260
-
261
- def record_vuln_solution(attrs)
262
- @report_data[:vuln_solution_stack] = []
263
- end
264
-
265
-
266
- def record_formatted_content(name, eattrs)
267
- attrs = attr_hash(eattrs)
268
- stack = nil
269
-
270
- if in_tag("solution")
271
- stack = @report_data[:vuln_solution_stack]
272
- end
273
-
274
- if in_tag("description")
275
- stack = @report_data[:vuln_description_stack]
276
- end
277
-
278
- if in_tag("test")
279
- stack = @report_data[:vuln_proof_stack]
280
- end
281
-
282
- return if not stack
283
-
284
- @report_data[:formatted_indent] ||= 0
285
-
286
- data = @text.to_s.strip.split(/\n+/).map{|t| t.strip}.join(" ")
287
- @text = ""
288
-
289
- case name
290
- when 'ListItem'
291
- @report_data[:formatted_indent] = 1
292
- # data = "\n* " + data
293
- when 'URLLink'
294
- @report_data[:formatted_link] = attrs["LinkURL"]
295
- else
296
-
297
- if @report_data[:formatted_indent] > 1
298
- data = (" " * (@report_data[:formatted_indent])) + data
299
- end
300
-
301
- if @report_data[:formatted_indent] == 1
302
- @report_data[:formatted_indent] = 6
303
- end
304
- end
305
-
306
- if data.length > 0
307
- stack << data
308
- end
309
- end
310
-
311
- def collect_formatted_content(name)
312
- stack = nil
313
- prefix = ""
314
-
315
- if in_tag("solution")
316
- stack = @report_data[:vuln_solution_stack]
317
- end
318
-
319
- if in_tag("description")
320
- stack = @report_data[:vuln_description_stack]
321
- end
322
-
323
- if in_tag("test")
324
- stack = @report_data[:vuln_proof_stack]
325
- end
326
-
327
- return if not stack
328
-
329
- data = @text.to_s.strip.split(/\n+/).map{|t| t.strip}.join(" ")
330
- @text = ""
331
-
332
- case name
333
- when 'URLLink'
334
- if @report_data[:formatted_link]
335
- if data != @report_data[:formatted_link]
336
- if data.empty?
337
- data << (" " + @report_data[:formatted_link])
338
- else
339
- data = " " + data + " ( " + @report_data[:formatted_link] + " )"
340
- end
341
- end
342
- end
343
- when 'Paragraph'
344
- data << "\n\n"
345
- when 'ListItem'
346
- @report_data[:formatted_indent] = 0
347
- data << "\n"
348
- end
349
-
350
- if data.length > 0
351
- stack << data
352
- end
353
- end
354
-
355
- # XML Export 2.0 includes additional test keys:
356
- # <test id="unix-unowned-files-or-dirs" status="vulnerable-exploited" scan-id="6381" vulnerable-since="20120322T124352665" pci-compliance-status="pass">
357
-
358
- def report_test
359
- return unless in_tag("nodes")
360
- return unless in_tag("node")
361
- return unless @state[:test]
362
-
363
- vuln_info = {
364
- :workspace => @args[:wspace],
365
- # This name will be overwritten during the vuln definition
366
- # parsing via mass-update.
367
- :name => "NEXPOSE-" + @state[:test][:id].downcase,
368
- :host => @state[:cached_host_object] || @state[:address]
369
- }
370
-
371
- if in_tag("endpoint") and @state[:test][:port]
372
- # Verify this port actually has some relation to our tracked state
373
- # since it may not due to greedy vulnerability matching
374
- if @state[:cached_service_object] and @state[:cached_service_object].port.to_i == @state[:test][:port].to_i
375
- vuln_info[:service] = @state[:cached_service_object]
376
- else
377
- vuln_info[:port] = @state[:test][:port]
378
- vuln_info[:proto] = @state[:test][:protocol] if @state[:test][:protocol]
379
- end
380
- end
381
-
382
- # This hash feeds a vuln_details row for this vulnerability
383
- vdet = { :src => 'nexpose', :nx_vuln_id => @state[:test][:id] }
384
-
385
- # This hash defines the matching criteria to overwrite an existing entry
386
- vkey = { :src => 'nexpose', :nx_vuln_id => @state[:test][:id] }
387
-
388
- if @state[:nx_device_id]
389
- vdet[:nx_device_id] = @state[:nx_device_id]
390
- vkey[:nx_device_id] = @state[:nx_device_id]
391
- end
392
-
393
- if @state[:test][:key]
394
- vdet[:nx_proof_key] = @state[:test][:key]
395
- vkey[:nx_proof_key] = @state[:test][:key]
396
- end
397
-
398
- vdet[:nx_console_id] = @nx_console_id if @nx_console_id
399
- vdet[:nx_vuln_status] = @state[:test][:status] if @state[:test][:status]
400
-
401
- vdet[:nx_scan_id] = @state[:test][:nx_scan_id] if @state[:test][:nx_scan_id]
402
- vdet[:nx_pci_compliance_status] = @state[:test][:nx_pci_compliance_status] if @state[:test][:nx_pci_compliance_status]
403
-
404
- if @state[:test][:nx_vulnerable_since]
405
- ts = ::DateTime.parse(@state[:test][:nx_vulnerable_since]) rescue nil
406
- vdet[:nx_vulnerable_since] = ts if ts
407
- end
408
-
409
- proof = clean_formatted_text(@report_data[:vuln_proof_stack].join.strip)
410
- @report_data[:vuln_proof_stack] = []
411
-
412
- vuln_info[:info] = proof
413
- vdet[:proof] = proof
414
-
415
- # Configure the find key for vuln_details
416
- vdet[:key] = vkey
417
-
418
- # Pass this key to the vuln hash to find existing entries
419
- # that may have been renamed (re-import nexpose vulns)
420
- vuln_info[:details_match] = vkey
421
-
422
- ::ActiveRecord::Base.connection_pool.with_connection {
423
-
424
- # Report the vulnerability
425
- vuln = db.report_vuln(vuln_info)
426
-
427
- if vuln
428
- # Report the vulnerability details
429
- detail = db.report_vuln_details(vuln, vdet)
430
-
431
- # Cache returned host and service objects if necessary
432
- @state[:cached_host_object] ||= vuln.host
433
-
434
- # The vuln.service may be found via greedy matching
435
- if in_tag("endpoint") and vuln.service
436
- @state[:cached_service_object] ||= vuln.service
437
- end
438
-
439
- # Record the ID of this vuln for a future mass update that
440
- # brings in title, risk, description, solution, etc
441
- @tests[ @state[:test][:id].downcase ] ||= []
442
- @tests[ @state[:test][:id].downcase ] << [ vuln.id, detail.id ]
443
- end
444
-
445
- }
446
- @state[:test] = nil
447
- end
448
-
449
- def record_os_fingerprint(attrs)
450
- return unless in_tag("nodes")
451
- return unless in_tag("fingerprints")
452
- return unless in_tag("node")
453
- return if in_tag("service")
454
- @state[:os] = attr_hash(attrs)
455
- end
456
-
457
- # Just keep the highest scoring, which is usually the most vague. :(
458
- def collect_os_fingerprints
459
- @report_data[:os] ||= {}
460
- return unless @state[:os]["certainty"].to_f > 0
461
- return if @report_data[:os]["os_certainty"].to_f > @state[:os]["certainty"].to_f
462
- @report_data[:os] = {} # Zero it out if we're replacing it.
463
- @report_data[:os]["os_certainty"] = @state[:os]["certainty"]
464
- @report_data[:os]["os_vendor"] = @state[:os]["vendor"]
465
- @report_data[:os]["os_family"] = @state[:os]["family"]
466
- @report_data[:os]["os_product"] = @state[:os]["product"]
467
- @report_data[:os]["os_version"] = @state[:os]["version"]
468
- @report_data[:os]["os_arch"] = @state[:os]["arch"]
469
- end
470
-
471
- # Just taking the first one.
472
- def collect_hostname
473
- if in_tag("node")
474
- @state[:hostname] ||= @text.to_s.strip if @text
475
- @text = nil
476
- end
477
- end
478
-
479
- def record_service_fingerprint(attrs)
480
- return unless in_tag("nodes")
481
- return unless in_tag("node")
482
- return unless in_tag("service")
483
- return unless in_tag("fingerprint")
484
- @state[:service_fingerprint] = attr_hash(attrs)
485
- end
486
-
487
- def record_service_info(attrs)
488
- return unless in_tag("nodes")
489
- return unless in_tag("node")
490
- return unless in_tag("service")
491
- @state[:service].merge! attr_hash(attrs)
492
- end
493
-
494
- def report_fingerprint(host_object)
495
- return unless host_object.kind_of? ::Mdm::Host
496
- return unless @report_data[:os].kind_of? Hash
497
- note = {
498
- :workspace => host_object.workspace,
499
- :host => host_object,
500
- :type => "host.os.nexpose_fingerprint",
501
- :data => {
502
- :family => @report_data[:os]["os_family"],
503
- :certainty => @report_data[:os]["os_certainty"]
504
- }
505
- }
506
- note[:data][:vendor] = @report_data[:os]["os_vendor"] if @report_data[:os]["os_vendor"]
507
- note[:data][:product] = @report_data[:os]["os_product"] if @report_data[:os]["os_prduct"]
508
- note[:data][:version] = @report_data[:os]["os_version"] if @report_data[:os]["os_version"]
509
- note[:data][:arch] = @report_data[:os]["os_arch"] if @report_data[:os]["os_arch"]
510
- db_report(:note, note)
511
- end
512
-
513
- def report_services(host_object)
514
- return unless host_object.kind_of? ::Mdm::Host
515
- return unless @report_data[:ports]
516
- return if @report_data[:ports].empty?
517
- reported = []
518
- @report_data[:ports].each do |svc|
519
- reported << db_report(:service, svc.merge(:host => host_object))
520
- end
521
- reported
522
- end
523
-
524
- def record_service(attrs)
525
- return unless in_tag("nodes")
526
- return unless in_tag("node")
527
- return unless in_tag("endpoint")
528
- @state[:service] = attr_hash(attrs)
529
- end
530
-
531
- def collect_service_data
532
- return unless in_tag("node")
533
- return unless in_tag("endpoint")
534
- port_hash = {}
535
- @report_data[:ports] ||= []
536
- @state[:service].each do |k,v|
537
- case k
538
- when "protocol"
539
- port_hash[:proto] = v
540
- when "port"
541
- port_hash[:port] = v
542
- when "status"
543
- port_hash[:status] = (v == "open" ? Msf::ServiceState::Open : Msf::ServiceState::Closed)
544
- end
545
- end
546
- if @state[:service]
547
- if state[:service]["name"] == "<unknown>"
548
- sname = nil
549
- else
550
- sname = db.service_name_map(@state[:service]["name"])
551
- end
552
- port_hash[:name] = sname
553
- end
554
- if @state[:service_fingerprint]
555
- info = []
556
- info << @state[:service_fingerprint]["product"] if @state[:service_fingerprint]["product"]
557
- info << @state[:service_fingerprint]["version"] if @state[:service_fingerprint]["version"]
558
- port_hash[:info] = info.join(" ") if info[0]
559
- end
560
- @report_data[:ports] << port_hash.clone
561
- @state.delete :service_fingerprint
562
- @state.delete :service
563
- @report_data[:ports]
564
- end
565
-
566
- def actually_vulnerable(test)
567
- return false unless test.has_key? "status"
568
- return false unless test.has_key? "id"
569
- ['vulnerable-exploited', 'vulnerable-version', 'potential'].include? test["status"]
570
- end
571
-
572
- def record_host_test(attrs)
573
- return unless in_tag("nodes")
574
- return unless in_tag("node")
575
- return if in_tag("service")
576
- return unless in_tag("tests")
577
-
578
- test = attr_hash(attrs)
579
- return unless actually_vulnerable(test)
580
- @state[:test] = {:id => test["id"].downcase}
581
- @state[:test][:key] = test["key"] if test["key"]
582
- @state[:test][:nx_scan_id] = test["scan-id"] if test["scan-id"]
583
- @state[:test][:nx_vulnerable_since] = test["vulnerable-since"] if test["vulnerable-since"]
584
- @state[:test][:nx_pci_compliance_status] = test["pci-compliance-status"] if test["pci-compliance-status"]
585
-
586
- @report_data[:vuln_proof_stack] = []
587
- end
588
-
589
- def record_service_test(attrs)
590
- return unless in_tag("nodes")
591
- return unless in_tag("node")
592
- return unless in_tag("service")
593
- return unless in_tag("tests")
594
- test = attr_hash(attrs)
595
- return unless actually_vulnerable(test)
596
- @state[:test] = {
597
- :id => test["id"].downcase,
598
- :port => @state[:service]["port"],
599
- :protocol => @state[:service]["protocol"],
600
- }
601
- @state[:test][:key] = test["key"] if test["key"]
602
- @state[:test][:status] = test["status"] if test["status"]
603
- @state[:test][:nx_scan_id] = test["scan-id"] if test["scan-id"]
604
- @state[:test][:nx_vulnerable_since] = test["vulnerable-since"] if test["vulnerable-since"]
605
- @state[:test][:nx_pci_compliance_status] = test["pci-compliance-status"] if test["pci-compliance-status"]
606
- @report_data[:vuln_proof_stack] = []
607
- end
608
-
609
- def record_host(attrs)
610
- return unless in_tag("nodes")
611
- host_attrs = attr_hash(attrs)
612
- if host_attrs["status"] == "alive"
613
- @state[:host_is_alive] = true
614
- @state[:address] = host_attrs["address"]
615
- @state[:mac] = host_attrs["hardware-address"] if host_attrs["hardware-address"]
616
-
617
- NEXPOSE_HOST_DETAIL_FIELDS.each do |f|
618
- fs = f.to_sym
619
- fk = f.sub(/^nx_/, '').gsub('_', '-')
620
- if host_attrs[fk]
621
- @state[fs] = host_attrs[fk]
622
- end
623
- end
624
- end
625
- end
626
-
627
- def collect_host_data
628
- return unless in_tag("node")
629
- @report_data[:host] = @state[:address]
630
- @report_data[:state] = Msf::HostState::Alive
631
- @report_data[:name] = @state[:hostname] if @state[:hostname]
632
- if @state[:mac]
633
- if @state[:mac] =~ /[0-9a-fA-f]{12}/
634
- @report_data[:mac] = @state[:mac].scan(/.{2}/).join(":")
635
- else
636
- @report_data[:mac] = @state[:mac]
637
- end
638
- end
639
-
640
- NEXPOSE_HOST_DETAIL_FIELDS.each do |f|
641
- v = @state[f.to_sym]
642
- @report_data[f.to_sym] = v if v
643
- end
644
- end
645
-
646
- def report_host(&block)
647
- if host_is_okay
648
- db.emit(:address,@report_data[:host],&block) if block
649
- device_id = @report_data[:nx_device_id]
650
-
651
- host_object = db_report(:host, @report_data.merge(:workspace => @args[:wspace] ) )
652
- if host_object
653
- db.report_import_note(host_object.workspace, host_object)
654
- if device_id
655
- detail = {
656
- :key => { :src => 'nexpose' },
657
- :src => 'nexpose',
658
- :nx_device_id => device_id
659
- }
660
- detail[:nx_console_id] = @nx_console_id if @nx_console_id
661
-
662
- NEXPOSE_HOST_DETAIL_FIELDS.each do |f|
663
- v = @report_data.delete(f.to_sym)
664
- detail[f.to_sym] = v if v
665
- end
666
-
667
-
668
- db.report_host_details(host_object, detail)
669
- end
670
- end
671
- host_object
672
- end
673
- end
674
-
675
- def clean_formatted_text(txt)
676
- txt.split(/\n/).map{ |t|
677
- t.sub(/^\s+$/, '').
678
- sub(/^(\s{6,20})/, ' ')
679
- }.join("\n").gsub(/\n{4,10}/, "\n\n\n")
680
- end
681
-
682
- end
6
+ module Parser
7
+
8
+ # If Nokogiri is available, define Template document class.
9
+ load_nokogiri && class NexposeRawDocument < Nokogiri::XML::SAX::Document
10
+
11
+ include NokogiriDocMixin
12
+
13
+ attr_reader :tests
14
+
15
+ NEXPOSE_HOST_DETAIL_FIELDS = %W{ nx_device_id nx_site_name nx_site_importance nx_scan_template nx_risk_score }
16
+ NEXPOSE_VULN_DETAIL_FIELDS = %W{
17
+ nx_scan_id
18
+ nx_vulnerable_since
19
+ nx_pci_compliance_status
20
+ }
21
+
22
+ # Triggered every time a new element is encountered. We keep state
23
+ # ourselves with the @state variable, turning things on when we
24
+ # get here (and turning things off when we exit in end_element()).
25
+ def start_element(name=nil,attrs=[])
26
+ attrs = normalize_attrs(attrs)
27
+ block = @block
28
+ @state[:current_tag][name] = true
29
+ case name
30
+ when "nodes" # There are two main sections, nodes and VulnerabilityDefinitions
31
+ @tests = {}
32
+ when "node"
33
+ record_host(attrs)
34
+ when "name"
35
+ @state[:has_text] = true
36
+ when "endpoint"
37
+ @state.delete(:cached_service_object)
38
+ record_service(attrs)
39
+ when "service"
40
+ record_service_info(attrs)
41
+ when "fingerprint"
42
+ record_service_fingerprint(attrs)
43
+ when "os"
44
+ record_os_fingerprint(attrs)
45
+ when "test" # All the vulns tested for
46
+ @state[:has_text] = true
47
+ record_host_test(attrs)
48
+ record_service_test(attrs)
49
+ when "vulnerability"
50
+ record_vuln(attrs)
51
+ when "reference"
52
+ @state[:has_text] = true
53
+ record_reference(attrs)
54
+ when "description"
55
+ @state[:has_text] = true
56
+ record_vuln_description(attrs)
57
+ when "solution"
58
+ @state[:has_text] = true
59
+ record_vuln_solution(attrs)
60
+ when "tag"
61
+ @state[:has_text] = true
62
+ when "tags"
63
+ @state[:tags] = []
64
+ #
65
+ # These are markup tags only present within description/solutions
66
+ #
67
+ when "ContainerBlockElement", # Overall container, no formatting
68
+ "Paragraph", # <Paragraph preformat="true">
69
+ "UnorderedList", # List container (bulleted)
70
+ "ListItem", # List item
71
+ "URLLink" # <URLLink LinkURL="http://support.microsoft.com/kb/887429" LinkTitle="http://support.microsoft.com/kb/887429" href="http://support.microsoft.com/kb/887429">KB 887429</URLLink>
72
+
73
+ record_formatted_content(name, attrs)
74
+
75
+ end
76
+ end
77
+
78
+ # When we exit a tag, this is triggered.
79
+ def end_element(name=nil)
80
+ block = @block
81
+ case name
82
+ when "node" # Wrap it up
83
+ collect_host_data
84
+ host_object = report_host &block
85
+ report_services(host_object)
86
+ report_fingerprint(host_object)
87
+ # Reset the state once we close a host
88
+ @state.delete_if {|k| k.to_s !~ /^(current_tag|in_nodes)$/}
89
+ @report_data = {:wspace => @args[:wspace]}
90
+ when "name"
91
+ collect_hostname
92
+ @state[:has_text] = false
93
+ @text = nil
94
+ when "endpoint"
95
+ collect_service_data
96
+ @state.delete(:cached_service_object)
97
+ when "os"
98
+ collect_os_fingerprints
99
+ when "test"
100
+ report_test(&block)
101
+ @state[:has_text] = false
102
+ @text = nil
103
+ when "vulnerability"
104
+ collect_vuln_info
105
+ report_vuln(&block)
106
+ @state.delete_if {|k| k.to_s !~ /^(current_tag|in_vulndefs)$/}
107
+ when "reference"
108
+ @state[:has_text] = false
109
+ collect_reference
110
+ @text = nil
111
+ when "description"
112
+ @state[:has_text] = false
113
+ collect_vuln_description
114
+ @text = nil
115
+ when "solution"
116
+ @state[:has_text] = false
117
+ collect_vuln_solution
118
+ @text = nil
119
+ when "tag"
120
+ @state[:has_text] = false
121
+ collect_tag
122
+ @text = nil
123
+ when "tags"
124
+ @report_data[:vuln_tags] = @state[:tags]
125
+ @state.delete(:tags)
126
+ #
127
+ # These are markup tags only present within description/solutions
128
+ #
129
+ when "ContainerBlockElement", # Overall container, no formatting
130
+ "Paragraph", # <Paragraph preformat="true">
131
+ "UnorderedList", # List container (bulleted)
132
+ "ListItem", # List item
133
+ "URLLink" # <URLLink LinkURL="http://support.microsoft.com/kb/887429" LinkTitle="http://support.microsoft.com/kb/887429" href="http://support.microsoft.com/kb/887429">KB 887429</URLLink>
134
+
135
+ collect_formatted_content(name)
136
+ end
137
+ @state[:current_tag].delete name
138
+ end
139
+
140
+ def collect_reference
141
+ return unless in_tag("references")
142
+ return unless in_tag("vulnerability")
143
+ return unless @state[:vuln]
144
+ @state[:ref][:value] = @text.to_s.strip
145
+ @report_data[:refs] ||= []
146
+ @report_data[:refs] << @state[:ref]
147
+ @state[:ref] = nil
148
+ end
149
+
150
+ def collect_vuln_description
151
+ return unless in_tag("description")
152
+ return unless in_tag("vulnerability")
153
+ return unless @state[:vuln]
154
+ @report_data[:vuln_description] = clean_formatted_text( @report_data[:vuln_description_stack].join.strip )
155
+ end
156
+
157
+ def collect_vuln_solution
158
+ return unless in_tag("solution")
159
+ return unless in_tag("vulnerability")
160
+ return unless @state[:vuln]
161
+ @report_data[:vuln_solution] = clean_formatted_text( @report_data[:vuln_solution_stack].join.strip )
162
+ end
163
+
164
+ def collect_tag
165
+ return unless in_tag("tag")
166
+ return unless in_tag("tags")
167
+ return unless in_tag("vulnerability")
168
+ return unless @state[:vuln]
169
+ @state[:tags] ||= []
170
+ @state[:tags] << @text.to_s.strip
171
+ end
172
+
173
+ def collect_vuln_info
174
+ return unless in_tag("VulnerabilityDefinitions")
175
+ return unless in_tag("vulnerability")
176
+ return unless @state[:vuln]
177
+ vuln = @state[:vuln]
178
+ vuln[:refs] = @report_data[:refs]
179
+ @report_data[:vuln] = vuln
180
+ @state[:vuln] = nil
181
+ @report_data[:refs] = nil
182
+ end
183
+
184
+ def report_vuln(&block)
185
+ return unless in_tag("VulnerabilityDefinitions")
186
+ return unless @report_data[:vuln]
187
+ return unless @report_data[:vuln][:matches].kind_of? Array
188
+
189
+ ::ActiveRecord::Base.connection_pool.with_connection {
190
+
191
+ refs = normalize_references(@report_data[:vuln][:refs])
192
+ refs << "NEXPOSE-#{report_data[:vuln]["id"]}"
193
+ vuln_instances = @report_data[:vuln][:matches].size
194
+ db.emit(:vuln, [refs.last,vuln_instances], &block) if block
195
+
196
+ vuln_ids = @report_data[:vuln][:matches].map{ |v| v[0] }
197
+ vdet_ids = @report_data[:vuln][:matches].map{ |v| v[1] }
198
+
199
+ refs = refs.uniq.map{|x| db.find_or_create_ref(:name => x) }
200
+
201
+ # Assign title and references to all vuln_ids
202
+ # Mass update fails due to the join table || ::Mdm::Vuln.where(:id => vuln_ids).update_all({ :name => @report_data[:vuln]["title"], :refs => refs } )
203
+ vuln_ids.each do |vid|
204
+ vuln = ::Mdm::Vuln.find(vid)
205
+ next unless vuln
206
+ vuln.name = @report_data[:vuln]["title"]
207
+
208
+ if refs.length > 0
209
+ vuln.refs += refs
210
+ end
211
+
212
+ if vuln.changed?
213
+ vuln.save!
214
+ end
215
+ end
216
+
217
+ # Mass update vulnerability details across the database based on conditions
218
+ vdet_info = { :title => @report_data[:vuln]["title"] }
219
+ vdet_info[:description] = @report_data[:vuln_description] unless @report_data[:vuln_description].to_s.empty?
220
+ vdet_info[:solution] = @report_data[:vuln_solution] unless @report_data[:vuln_solution].to_s.empty?
221
+ vdet_info[:nx_tags] = @report_data[:vuln_tags].sort.uniq.join(", ") if ( @report_data[:vuln_tags].kind_of?(::Array) and @report_data[:vuln_tags].length > 0 )
222
+ vdet_info[:nx_severity] = @report_data[:vuln]["severity"].to_f if @report_data[:vuln]["severity"]
223
+ vdet_info[:nx_pci_severity] = @report_data[:vuln]["pciSeverity"].to_f if @report_data[:vuln]["pciSeverity"]
224
+ vdet_info[:cvss_score] = @report_data[:vuln]["cvssScore"].to_f if @report_data[:vuln]["cvssScore"]
225
+ vdet_info[:cvss_vector] = @report_data[:vuln]["cvssVector"] if @report_data[:vuln]["cvssVector"]
226
+
227
+ %W{ published added modified }.each do |tf|
228
+ next if not @report_data[:vuln][tf]
229
+ ts = DateTime.parse(@report_data[:vuln][tf]) rescue nil
230
+ next if not ts
231
+ vdet_info[ "nx_#{tf}".to_sym ] = ts
232
+ end
233
+
234
+ ::Mdm::VulnDetail.where(:id => vdet_ids).update_all(vdet_info)
235
+
236
+ @report_data[:vuln] = nil
237
+
238
+ }
239
+ end
240
+
241
+ def record_reference(attrs)
242
+ return unless in_tag("VulnerabilityDefinitions")
243
+ return unless in_tag("vulnerability")
244
+ @state[:ref] = attr_hash(attrs)
245
+ end
246
+
247
+ def record_vuln(attrs)
248
+ return unless in_tag("VulnerabilityDefinitions")
249
+ vuln = attr_hash(attrs)
250
+ matching_tests = @tests[ vuln["id"].downcase ]
251
+ return unless matching_tests
252
+ return if matching_tests.empty?
253
+ @state[:vuln] = vuln
254
+ @state[:vuln][:matches] = matching_tests
255
+ end
256
+
257
+ def record_vuln_description(attrs)
258
+ @report_data[:vuln_description_stack] = []
259
+ end
260
+
261
+ def record_vuln_solution(attrs)
262
+ @report_data[:vuln_solution_stack] = []
263
+ end
264
+
265
+
266
+ def record_formatted_content(name, eattrs)
267
+ attrs = attr_hash(eattrs)
268
+ stack = nil
269
+
270
+ if in_tag("solution")
271
+ stack = @report_data[:vuln_solution_stack]
272
+ end
273
+
274
+ if in_tag("description")
275
+ stack = @report_data[:vuln_description_stack]
276
+ end
277
+
278
+ if in_tag("test")
279
+ stack = @report_data[:vuln_proof_stack]
280
+ end
281
+
282
+ return if not stack
283
+
284
+ @report_data[:formatted_indent] ||= 0
285
+
286
+ data = @text.to_s.strip.split(/\n+/).map{|t| t.strip}.join(" ")
287
+ @text = ""
288
+
289
+ case name
290
+ when 'ListItem'
291
+ @report_data[:formatted_indent] = 1
292
+ # data = "\n* " + data
293
+ when 'URLLink'
294
+ @report_data[:formatted_link] = attrs["LinkURL"]
295
+ else
296
+
297
+ if @report_data[:formatted_indent] > 1
298
+ data = (" " * (@report_data[:formatted_indent])) + data
299
+ end
300
+
301
+ if @report_data[:formatted_indent] == 1
302
+ @report_data[:formatted_indent] = 6
303
+ end
304
+ end
305
+
306
+ if data.length > 0
307
+ stack << data
308
+ end
309
+ end
310
+
311
+ def collect_formatted_content(name)
312
+ stack = nil
313
+ prefix = ""
314
+
315
+ if in_tag("solution")
316
+ stack = @report_data[:vuln_solution_stack]
317
+ end
318
+
319
+ if in_tag("description")
320
+ stack = @report_data[:vuln_description_stack]
321
+ end
322
+
323
+ if in_tag("test")
324
+ stack = @report_data[:vuln_proof_stack]
325
+ end
326
+
327
+ return if not stack
328
+
329
+ data = @text.to_s.strip.split(/\n+/).map{|t| t.strip}.join(" ")
330
+ @text = ""
331
+
332
+ case name
333
+ when 'URLLink'
334
+ if @report_data[:formatted_link]
335
+ if data != @report_data[:formatted_link]
336
+ if data.empty?
337
+ data << (" " + @report_data[:formatted_link])
338
+ else
339
+ data = " " + data + " ( " + @report_data[:formatted_link] + " )"
340
+ end
341
+ end
342
+ end
343
+ when 'Paragraph'
344
+ data << "\n\n"
345
+ when 'ListItem'
346
+ @report_data[:formatted_indent] = 0
347
+ data << "\n"
348
+ end
349
+
350
+ if data.length > 0
351
+ stack << data
352
+ end
353
+ end
354
+
355
+ # XML Export 2.0 includes additional test keys:
356
+ # <test id="unix-unowned-files-or-dirs" status="vulnerable-exploited" scan-id="6381" vulnerable-since="20120322T124352665" pci-compliance-status="pass">
357
+
358
+ def report_test
359
+ return unless in_tag("nodes")
360
+ return unless in_tag("node")
361
+ return unless @state[:test]
362
+
363
+ vuln_info = {
364
+ :workspace => @args[:wspace],
365
+ # This name will be overwritten during the vuln definition
366
+ # parsing via mass-update.
367
+ :name => "NEXPOSE-" + @state[:test][:id].downcase,
368
+ :host => @state[:cached_host_object] || @state[:address]
369
+ }
370
+
371
+ if in_tag("endpoint") and @state[:test][:port]
372
+ # Verify this port actually has some relation to our tracked state
373
+ # since it may not due to greedy vulnerability matching
374
+ if @state[:cached_service_object] and @state[:cached_service_object].port.to_i == @state[:test][:port].to_i
375
+ vuln_info[:service] = @state[:cached_service_object]
376
+ else
377
+ vuln_info[:port] = @state[:test][:port]
378
+ vuln_info[:proto] = @state[:test][:protocol] if @state[:test][:protocol]
379
+ end
380
+ end
381
+
382
+ # This hash feeds a vuln_details row for this vulnerability
383
+ vdet = { :src => 'nexpose', :nx_vuln_id => @state[:test][:id] }
384
+
385
+ # This hash defines the matching criteria to overwrite an existing entry
386
+ vkey = { :src => 'nexpose', :nx_vuln_id => @state[:test][:id] }
387
+
388
+ if @state[:nx_device_id]
389
+ vdet[:nx_device_id] = @state[:nx_device_id]
390
+ vkey[:nx_device_id] = @state[:nx_device_id]
391
+ end
392
+
393
+ if @state[:test][:key]
394
+ vdet[:nx_proof_key] = @state[:test][:key]
395
+ vkey[:nx_proof_key] = @state[:test][:key]
396
+ end
397
+
398
+ vdet[:nx_console_id] = @nx_console_id if @nx_console_id
399
+ vdet[:nx_vuln_status] = @state[:test][:status] if @state[:test][:status]
400
+
401
+ vdet[:nx_scan_id] = @state[:test][:nx_scan_id] if @state[:test][:nx_scan_id]
402
+ vdet[:nx_pci_compliance_status] = @state[:test][:nx_pci_compliance_status] if @state[:test][:nx_pci_compliance_status]
403
+
404
+ if @state[:test][:nx_vulnerable_since]
405
+ ts = ::DateTime.parse(@state[:test][:nx_vulnerable_since]) rescue nil
406
+ vdet[:nx_vulnerable_since] = ts if ts
407
+ end
408
+
409
+ proof = clean_formatted_text(@report_data[:vuln_proof_stack].join.strip)
410
+ @report_data[:vuln_proof_stack] = []
411
+
412
+ vuln_info[:info] = proof
413
+ vdet[:proof] = proof
414
+
415
+ # Configure the find key for vuln_details
416
+ vdet[:key] = vkey
417
+
418
+ # Pass this key to the vuln hash to find existing entries
419
+ # that may have been renamed (re-import nexpose vulns)
420
+ vuln_info[:details_match] = vkey
421
+
422
+ ::ActiveRecord::Base.connection_pool.with_connection {
423
+
424
+ # Report the vulnerability
425
+ vuln = db.report_vuln(vuln_info)
426
+
427
+ if vuln
428
+ # Report the vulnerability details
429
+ detail = db.report_vuln_details(vuln, vdet)
430
+
431
+ # Cache returned host and service objects if necessary
432
+ @state[:cached_host_object] ||= vuln.host
433
+
434
+ # The vuln.service may be found via greedy matching
435
+ if in_tag("endpoint") and vuln.service
436
+ @state[:cached_service_object] ||= vuln.service
437
+ end
438
+
439
+ # Record the ID of this vuln for a future mass update that
440
+ # brings in title, risk, description, solution, etc
441
+ @tests[ @state[:test][:id].downcase ] ||= []
442
+ @tests[ @state[:test][:id].downcase ] << [ vuln.id, detail.id ]
443
+ end
444
+
445
+ }
446
+ @state[:test] = nil
447
+ end
448
+
449
+ def record_os_fingerprint(attrs)
450
+ return unless in_tag("nodes")
451
+ return unless in_tag("fingerprints")
452
+ return unless in_tag("node")
453
+ return if in_tag("service")
454
+ @state[:os] = attr_hash(attrs)
455
+ end
456
+
457
+ # Just keep the highest scoring, which is usually the most vague. :(
458
+ def collect_os_fingerprints
459
+ @report_data[:os] ||= {}
460
+ return unless @state[:os]["certainty"].to_f > 0
461
+ return if @report_data[:os]["os_certainty"].to_f > @state[:os]["certainty"].to_f
462
+ @report_data[:os] = {} # Zero it out if we're replacing it.
463
+ @report_data[:os]["os_certainty"] = @state[:os]["certainty"]
464
+ @report_data[:os]["os_vendor"] = @state[:os]["vendor"]
465
+ @report_data[:os]["os_family"] = @state[:os]["family"]
466
+ @report_data[:os]["os_product"] = @state[:os]["product"]
467
+ @report_data[:os]["os_version"] = @state[:os]["version"]
468
+ @report_data[:os]["os_arch"] = @state[:os]["arch"]
469
+ end
470
+
471
+ # Just taking the first one.
472
+ def collect_hostname
473
+ if in_tag("node")
474
+ @state[:hostname] ||= @text.to_s.strip if @text
475
+ @text = nil
476
+ end
477
+ end
478
+
479
+ def record_service_fingerprint(attrs)
480
+ return unless in_tag("nodes")
481
+ return unless in_tag("node")
482
+ return unless in_tag("service")
483
+ return unless in_tag("fingerprint")
484
+ @state[:service_fingerprint] = attr_hash(attrs)
485
+ end
486
+
487
+ def record_service_info(attrs)
488
+ return unless in_tag("nodes")
489
+ return unless in_tag("node")
490
+ return unless in_tag("service")
491
+ @state[:service].merge! attr_hash(attrs)
492
+ end
493
+
494
+ def report_fingerprint(host_object)
495
+ return unless host_object.kind_of? ::Mdm::Host
496
+ return unless @report_data[:os].kind_of? Hash
497
+ note = {
498
+ :workspace => host_object.workspace,
499
+ :host => host_object,
500
+ :type => "host.os.nexpose_fingerprint",
501
+ :data => {
502
+ :family => @report_data[:os]["os_family"],
503
+ :certainty => @report_data[:os]["os_certainty"]
504
+ }
505
+ }
506
+ note[:data][:vendor] = @report_data[:os]["os_vendor"] if @report_data[:os]["os_vendor"]
507
+ note[:data][:product] = @report_data[:os]["os_product"] if @report_data[:os]["os_prduct"]
508
+ note[:data][:version] = @report_data[:os]["os_version"] if @report_data[:os]["os_version"]
509
+ note[:data][:arch] = @report_data[:os]["os_arch"] if @report_data[:os]["os_arch"]
510
+ db_report(:note, note)
511
+ end
512
+
513
+ def report_services(host_object)
514
+ return unless host_object.kind_of? ::Mdm::Host
515
+ return unless @report_data[:ports]
516
+ return if @report_data[:ports].empty?
517
+ reported = []
518
+ @report_data[:ports].each do |svc|
519
+ reported << db_report(:service, svc.merge(:host => host_object))
520
+ end
521
+ reported
522
+ end
523
+
524
+ def record_service(attrs)
525
+ return unless in_tag("nodes")
526
+ return unless in_tag("node")
527
+ return unless in_tag("endpoint")
528
+ @state[:service] = attr_hash(attrs)
529
+ end
530
+
531
+ def collect_service_data
532
+ return unless in_tag("node")
533
+ return unless in_tag("endpoint")
534
+ port_hash = {}
535
+ @report_data[:ports] ||= []
536
+ @state[:service].each do |k,v|
537
+ case k
538
+ when "protocol"
539
+ port_hash[:proto] = v
540
+ when "port"
541
+ port_hash[:port] = v
542
+ when "status"
543
+ port_hash[:status] = (v == "open" ? Msf::ServiceState::Open : Msf::ServiceState::Closed)
544
+ end
545
+ end
546
+ if @state[:service]
547
+ if state[:service]["name"] == "<unknown>"
548
+ sname = nil
549
+ else
550
+ sname = db.service_name_map(@state[:service]["name"])
551
+ end
552
+ port_hash[:name] = sname
553
+ end
554
+ if @state[:service_fingerprint]
555
+ info = []
556
+ info << @state[:service_fingerprint]["product"] if @state[:service_fingerprint]["product"]
557
+ info << @state[:service_fingerprint]["version"] if @state[:service_fingerprint]["version"]
558
+ port_hash[:info] = info.join(" ") if info[0]
559
+ end
560
+ @report_data[:ports] << port_hash.clone
561
+ @state.delete :service_fingerprint
562
+ @state.delete :service
563
+ @report_data[:ports]
564
+ end
565
+
566
+ def actually_vulnerable(test)
567
+ return false unless test.has_key? "status"
568
+ return false unless test.has_key? "id"
569
+ ['vulnerable-exploited', 'vulnerable-version', 'potential'].include? test["status"]
570
+ end
571
+
572
+ def record_host_test(attrs)
573
+ return unless in_tag("nodes")
574
+ return unless in_tag("node")
575
+ return if in_tag("service")
576
+ return unless in_tag("tests")
577
+
578
+ test = attr_hash(attrs)
579
+ return unless actually_vulnerable(test)
580
+ @state[:test] = {:id => test["id"].downcase}
581
+ @state[:test][:key] = test["key"] if test["key"]
582
+ @state[:test][:nx_scan_id] = test["scan-id"] if test["scan-id"]
583
+ @state[:test][:nx_vulnerable_since] = test["vulnerable-since"] if test["vulnerable-since"]
584
+ @state[:test][:nx_pci_compliance_status] = test["pci-compliance-status"] if test["pci-compliance-status"]
585
+
586
+ @report_data[:vuln_proof_stack] = []
587
+ end
588
+
589
+ def record_service_test(attrs)
590
+ return unless in_tag("nodes")
591
+ return unless in_tag("node")
592
+ return unless in_tag("service")
593
+ return unless in_tag("tests")
594
+ test = attr_hash(attrs)
595
+ return unless actually_vulnerable(test)
596
+ @state[:test] = {
597
+ :id => test["id"].downcase,
598
+ :port => @state[:service]["port"],
599
+ :protocol => @state[:service]["protocol"],
600
+ }
601
+ @state[:test][:key] = test["key"] if test["key"]
602
+ @state[:test][:status] = test["status"] if test["status"]
603
+ @state[:test][:nx_scan_id] = test["scan-id"] if test["scan-id"]
604
+ @state[:test][:nx_vulnerable_since] = test["vulnerable-since"] if test["vulnerable-since"]
605
+ @state[:test][:nx_pci_compliance_status] = test["pci-compliance-status"] if test["pci-compliance-status"]
606
+ @report_data[:vuln_proof_stack] = []
607
+ end
608
+
609
+ def record_host(attrs)
610
+ return unless in_tag("nodes")
611
+ host_attrs = attr_hash(attrs)
612
+ if host_attrs["status"] == "alive"
613
+ @state[:host_is_alive] = true
614
+ @state[:address] = host_attrs["address"]
615
+ @state[:mac] = host_attrs["hardware-address"] if host_attrs["hardware-address"]
616
+
617
+ NEXPOSE_HOST_DETAIL_FIELDS.each do |f|
618
+ fs = f.to_sym
619
+ fk = f.sub(/^nx_/, '').gsub('_', '-')
620
+ if host_attrs[fk]
621
+ @state[fs] = host_attrs[fk]
622
+ end
623
+ end
624
+ end
625
+ end
626
+
627
+ def collect_host_data
628
+ return unless in_tag("node")
629
+ @report_data[:host] = @state[:address]
630
+ @report_data[:state] = Msf::HostState::Alive
631
+ @report_data[:name] = @state[:hostname] if @state[:hostname]
632
+ if @state[:mac]
633
+ if @state[:mac] =~ /[0-9a-fA-f]{12}/
634
+ @report_data[:mac] = @state[:mac].scan(/.{2}/).join(":")
635
+ else
636
+ @report_data[:mac] = @state[:mac]
637
+ end
638
+ end
639
+
640
+ NEXPOSE_HOST_DETAIL_FIELDS.each do |f|
641
+ v = @state[f.to_sym]
642
+ @report_data[f.to_sym] = v if v
643
+ end
644
+ end
645
+
646
+ def report_host(&block)
647
+ if host_is_okay
648
+ db.emit(:address,@report_data[:host],&block) if block
649
+ device_id = @report_data[:nx_device_id]
650
+
651
+ host_object = db_report(:host, @report_data.merge(:workspace => @args[:wspace] ) )
652
+ if host_object
653
+ db.report_import_note(host_object.workspace, host_object)
654
+ if device_id
655
+ detail = {
656
+ :key => { :src => 'nexpose' },
657
+ :src => 'nexpose',
658
+ :nx_device_id => device_id
659
+ }
660
+ detail[:nx_console_id] = @nx_console_id if @nx_console_id
661
+
662
+ NEXPOSE_HOST_DETAIL_FIELDS.each do |f|
663
+ v = @report_data.delete(f.to_sym)
664
+ detail[f.to_sym] = v if v
665
+ end
666
+
667
+
668
+ db.report_host_details(host_object, detail)
669
+ end
670
+ end
671
+ host_object
672
+ end
673
+ end
674
+
675
+ def clean_formatted_text(txt)
676
+ txt.split(/\n/).map{ |t|
677
+ t.sub(/^\s+$/, '').
678
+ sub(/^(\s{6,20})/, ' ')
679
+ }.join("\n").gsub(/\n{4,10}/, "\n\n\n")
680
+ end
681
+
682
+ end
683
683
 
684
684
  end
685
685
  end