dstruct 0.0.1

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 (491) hide show
  1. checksums.yaml +15 -0
  2. data/README.markdown +23 -0
  3. data/examples/smb_example.rb +35 -0
  4. data/lib/rex.rb +108 -0
  5. data/lib/rex/LICENSE +29 -0
  6. data/lib/rex/arch.rb +104 -0
  7. data/lib/rex/arch/sparc.rb +75 -0
  8. data/lib/rex/arch/x86.rb +524 -0
  9. data/lib/rex/assembly/nasm.rb +104 -0
  10. data/lib/rex/codepage.map +104 -0
  11. data/lib/rex/compat.rb +389 -0
  12. data/lib/rex/constants.rb +124 -0
  13. data/lib/rex/elfparsey.rb +9 -0
  14. data/lib/rex/elfparsey/elf.rb +121 -0
  15. data/lib/rex/elfparsey/elfbase.rb +256 -0
  16. data/lib/rex/elfparsey/exceptions.rb +25 -0
  17. data/lib/rex/elfscan.rb +10 -0
  18. data/lib/rex/elfscan/scanner.rb +226 -0
  19. data/lib/rex/elfscan/search.rb +44 -0
  20. data/lib/rex/encoder/alpha2.rb +31 -0
  21. data/lib/rex/encoder/alpha2/alpha_mixed.rb +68 -0
  22. data/lib/rex/encoder/alpha2/alpha_upper.rb +79 -0
  23. data/lib/rex/encoder/alpha2/generic.rb +90 -0
  24. data/lib/rex/encoder/alpha2/unicode_mixed.rb +116 -0
  25. data/lib/rex/encoder/alpha2/unicode_upper.rb +123 -0
  26. data/lib/rex/encoder/bloxor/bloxor.rb +327 -0
  27. data/lib/rex/encoder/ndr.rb +90 -0
  28. data/lib/rex/encoder/nonalpha.rb +61 -0
  29. data/lib/rex/encoder/nonupper.rb +64 -0
  30. data/lib/rex/encoder/xdr.rb +107 -0
  31. data/lib/rex/encoder/xor.rb +69 -0
  32. data/lib/rex/encoder/xor/dword.rb +13 -0
  33. data/lib/rex/encoder/xor/dword_additive.rb +13 -0
  34. data/lib/rex/encoders/xor_dword.rb +35 -0
  35. data/lib/rex/encoders/xor_dword_additive.rb +53 -0
  36. data/lib/rex/encoding/xor.rb +20 -0
  37. data/lib/rex/encoding/xor/byte.rb +15 -0
  38. data/lib/rex/encoding/xor/dword.rb +21 -0
  39. data/lib/rex/encoding/xor/dword_additive.rb +92 -0
  40. data/lib/rex/encoding/xor/exceptions.rb +17 -0
  41. data/lib/rex/encoding/xor/generic.rb +146 -0
  42. data/lib/rex/encoding/xor/qword.rb +15 -0
  43. data/lib/rex/encoding/xor/word.rb +21 -0
  44. data/lib/rex/exceptions.rb +275 -0
  45. data/lib/rex/exploitation/cmdstager.rb +10 -0
  46. data/lib/rex/exploitation/cmdstager/base.rb +190 -0
  47. data/lib/rex/exploitation/cmdstager/bourne.rb +105 -0
  48. data/lib/rex/exploitation/cmdstager/debug_asm.rb +140 -0
  49. data/lib/rex/exploitation/cmdstager/debug_write.rb +134 -0
  50. data/lib/rex/exploitation/cmdstager/echo.rb +164 -0
  51. data/lib/rex/exploitation/cmdstager/printf.rb +122 -0
  52. data/lib/rex/exploitation/cmdstager/tftp.rb +71 -0
  53. data/lib/rex/exploitation/cmdstager/vbs.rb +126 -0
  54. data/lib/rex/exploitation/egghunter.rb +425 -0
  55. data/lib/rex/exploitation/encryptjs.rb +78 -0
  56. data/lib/rex/exploitation/heaplib.js.b64 +331 -0
  57. data/lib/rex/exploitation/heaplib.rb +107 -0
  58. data/lib/rex/exploitation/js.rb +6 -0
  59. data/lib/rex/exploitation/js/detect.rb +69 -0
  60. data/lib/rex/exploitation/js/memory.rb +81 -0
  61. data/lib/rex/exploitation/js/network.rb +84 -0
  62. data/lib/rex/exploitation/js/utils.rb +33 -0
  63. data/lib/rex/exploitation/jsobfu.rb +513 -0
  64. data/lib/rex/exploitation/obfuscatejs.rb +336 -0
  65. data/lib/rex/exploitation/omelet.rb +321 -0
  66. data/lib/rex/exploitation/opcodedb.rb +819 -0
  67. data/lib/rex/exploitation/powershell.rb +62 -0
  68. data/lib/rex/exploitation/powershell/function.rb +63 -0
  69. data/lib/rex/exploitation/powershell/obfu.rb +98 -0
  70. data/lib/rex/exploitation/powershell/output.rb +151 -0
  71. data/lib/rex/exploitation/powershell/param.rb +23 -0
  72. data/lib/rex/exploitation/powershell/parser.rb +183 -0
  73. data/lib/rex/exploitation/powershell/psh_methods.rb +70 -0
  74. data/lib/rex/exploitation/powershell/script.rb +99 -0
  75. data/lib/rex/exploitation/ropdb.rb +190 -0
  76. data/lib/rex/exploitation/seh.rb +93 -0
  77. data/lib/rex/file.rb +160 -0
  78. data/lib/rex/image_source.rb +10 -0
  79. data/lib/rex/image_source/disk.rb +58 -0
  80. data/lib/rex/image_source/image_source.rb +44 -0
  81. data/lib/rex/image_source/memory.rb +35 -0
  82. data/lib/rex/io/bidirectional_pipe.rb +161 -0
  83. data/lib/rex/io/datagram_abstraction.rb +35 -0
  84. data/lib/rex/io/ring_buffer.rb +369 -0
  85. data/lib/rex/io/stream.rb +312 -0
  86. data/lib/rex/io/stream_abstraction.rb +209 -0
  87. data/lib/rex/io/stream_server.rb +221 -0
  88. data/lib/rex/job_container.rb +200 -0
  89. data/lib/rex/logging.rb +4 -0
  90. data/lib/rex/logging/log_dispatcher.rb +180 -0
  91. data/lib/rex/logging/log_sink.rb +43 -0
  92. data/lib/rex/logging/sinks/flatfile.rb +56 -0
  93. data/lib/rex/logging/sinks/stderr.rb +44 -0
  94. data/lib/rex/mac_oui.rb +16581 -0
  95. data/lib/rex/machparsey.rb +9 -0
  96. data/lib/rex/machparsey/exceptions.rb +34 -0
  97. data/lib/rex/machparsey/mach.rb +209 -0
  98. data/lib/rex/machparsey/machbase.rb +408 -0
  99. data/lib/rex/machscan.rb +9 -0
  100. data/lib/rex/machscan/scanner.rb +217 -0
  101. data/lib/rex/mime.rb +10 -0
  102. data/lib/rex/mime/encoding.rb +17 -0
  103. data/lib/rex/mime/header.rb +78 -0
  104. data/lib/rex/mime/message.rb +150 -0
  105. data/lib/rex/mime/part.rb +50 -0
  106. data/lib/rex/nop/opty2.rb +109 -0
  107. data/lib/rex/nop/opty2_tables.rb +301 -0
  108. data/lib/rex/ole.rb +202 -0
  109. data/lib/rex/ole/clsid.rb +44 -0
  110. data/lib/rex/ole/difat.rb +138 -0
  111. data/lib/rex/ole/directory.rb +228 -0
  112. data/lib/rex/ole/direntry.rb +237 -0
  113. data/lib/rex/ole/docs/dependencies.txt +8 -0
  114. data/lib/rex/ole/docs/references.txt +1 -0
  115. data/lib/rex/ole/fat.rb +96 -0
  116. data/lib/rex/ole/header.rb +201 -0
  117. data/lib/rex/ole/minifat.rb +74 -0
  118. data/lib/rex/ole/propset.rb +141 -0
  119. data/lib/rex/ole/samples/create_ole.rb +27 -0
  120. data/lib/rex/ole/samples/dir.rb +35 -0
  121. data/lib/rex/ole/samples/dump_stream.rb +34 -0
  122. data/lib/rex/ole/samples/ole_info.rb +23 -0
  123. data/lib/rex/ole/storage.rb +392 -0
  124. data/lib/rex/ole/stream.rb +50 -0
  125. data/lib/rex/ole/substorage.rb +46 -0
  126. data/lib/rex/ole/util.rb +154 -0
  127. data/lib/rex/parser/acunetix_nokogiri.rb +406 -0
  128. data/lib/rex/parser/apple_backup_manifestdb.rb +132 -0
  129. data/lib/rex/parser/appscan_nokogiri.rb +367 -0
  130. data/lib/rex/parser/arguments.rb +108 -0
  131. data/lib/rex/parser/burp_session_nokogiri.rb +291 -0
  132. data/lib/rex/parser/ci_nokogiri.rb +193 -0
  133. data/lib/rex/parser/foundstone_nokogiri.rb +342 -0
  134. data/lib/rex/parser/fusionvm_nokogiri.rb +109 -0
  135. data/lib/rex/parser/group_policy_preferences.rb +185 -0
  136. data/lib/rex/parser/ini.rb +186 -0
  137. data/lib/rex/parser/ip360_aspl_xml.rb +103 -0
  138. data/lib/rex/parser/ip360_xml.rb +98 -0
  139. data/lib/rex/parser/mbsa_nokogiri.rb +256 -0
  140. data/lib/rex/parser/nessus_xml.rb +121 -0
  141. data/lib/rex/parser/netsparker_xml.rb +109 -0
  142. data/lib/rex/parser/nexpose_raw_nokogiri.rb +686 -0
  143. data/lib/rex/parser/nexpose_simple_nokogiri.rb +330 -0
  144. data/lib/rex/parser/nexpose_xml.rb +172 -0
  145. data/lib/rex/parser/nmap_nokogiri.rb +394 -0
  146. data/lib/rex/parser/nmap_xml.rb +166 -0
  147. data/lib/rex/parser/nokogiri_doc_mixin.rb +233 -0
  148. data/lib/rex/parser/openvas_nokogiri.rb +172 -0
  149. data/lib/rex/parser/outpost24_nokogiri.rb +240 -0
  150. data/lib/rex/parser/retina_xml.rb +110 -0
  151. data/lib/rex/parser/unattend.rb +171 -0
  152. data/lib/rex/parser/wapiti_nokogiri.rb +105 -0
  153. data/lib/rex/payloads.rb +2 -0
  154. data/lib/rex/payloads/win32.rb +3 -0
  155. data/lib/rex/payloads/win32/common.rb +27 -0
  156. data/lib/rex/payloads/win32/kernel.rb +54 -0
  157. data/lib/rex/payloads/win32/kernel/common.rb +55 -0
  158. data/lib/rex/payloads/win32/kernel/migration.rb +13 -0
  159. data/lib/rex/payloads/win32/kernel/recovery.rb +51 -0
  160. data/lib/rex/payloads/win32/kernel/stager.rb +195 -0
  161. data/lib/rex/peparsey.rb +10 -0
  162. data/lib/rex/peparsey/exceptions.rb +30 -0
  163. data/lib/rex/peparsey/pe.rb +210 -0
  164. data/lib/rex/peparsey/pe_memdump.rb +61 -0
  165. data/lib/rex/peparsey/pebase.rb +1662 -0
  166. data/lib/rex/peparsey/section.rb +128 -0
  167. data/lib/rex/pescan.rb +11 -0
  168. data/lib/rex/pescan/analyze.rb +366 -0
  169. data/lib/rex/pescan/scanner.rb +230 -0
  170. data/lib/rex/pescan/search.rb +68 -0
  171. data/lib/rex/platforms.rb +2 -0
  172. data/lib/rex/platforms/windows.rb +52 -0
  173. data/lib/rex/poly.rb +134 -0
  174. data/lib/rex/poly/block.rb +480 -0
  175. data/lib/rex/poly/machine.rb +13 -0
  176. data/lib/rex/poly/machine/machine.rb +830 -0
  177. data/lib/rex/poly/machine/x86.rb +509 -0
  178. data/lib/rex/poly/register.rb +101 -0
  179. data/lib/rex/poly/register/x86.rb +41 -0
  180. data/lib/rex/post.rb +7 -0
  181. data/lib/rex/post/dir.rb +51 -0
  182. data/lib/rex/post/file.rb +172 -0
  183. data/lib/rex/post/file_stat.rb +220 -0
  184. data/lib/rex/post/gen.pl +13 -0
  185. data/lib/rex/post/io.rb +182 -0
  186. data/lib/rex/post/meterpreter.rb +5 -0
  187. data/lib/rex/post/meterpreter/channel.rb +446 -0
  188. data/lib/rex/post/meterpreter/channel_container.rb +54 -0
  189. data/lib/rex/post/meterpreter/channels/pool.rb +160 -0
  190. data/lib/rex/post/meterpreter/channels/pools/file.rb +62 -0
  191. data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +103 -0
  192. data/lib/rex/post/meterpreter/channels/stream.rb +87 -0
  193. data/lib/rex/post/meterpreter/client.rb +483 -0
  194. data/lib/rex/post/meterpreter/client_core.rb +352 -0
  195. data/lib/rex/post/meterpreter/dependencies.rb +3 -0
  196. data/lib/rex/post/meterpreter/extension.rb +32 -0
  197. data/lib/rex/post/meterpreter/extensions/android/android.rb +128 -0
  198. data/lib/rex/post/meterpreter/extensions/android/tlv.rb +40 -0
  199. data/lib/rex/post/meterpreter/extensions/espia/espia.rb +58 -0
  200. data/lib/rex/post/meterpreter/extensions/espia/tlv.rb +17 -0
  201. data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +71 -0
  202. data/lib/rex/post/meterpreter/extensions/extapi/clipboard/clipboard.rb +169 -0
  203. data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +45 -0
  204. data/lib/rex/post/meterpreter/extensions/extapi/service/service.rb +104 -0
  205. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +77 -0
  206. data/lib/rex/post/meterpreter/extensions/extapi/window/window.rb +56 -0
  207. data/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb +75 -0
  208. data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +94 -0
  209. data/lib/rex/post/meterpreter/extensions/incognito/tlv.rb +22 -0
  210. data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +361 -0
  211. data/lib/rex/post/meterpreter/extensions/kiwi/tlv.rb +76 -0
  212. data/lib/rex/post/meterpreter/extensions/lanattacks/dhcp/dhcp.rb +78 -0
  213. data/lib/rex/post/meterpreter/extensions/lanattacks/lanattacks.rb +43 -0
  214. data/lib/rex/post/meterpreter/extensions/lanattacks/tftp/tftp.rb +49 -0
  215. data/lib/rex/post/meterpreter/extensions/lanattacks/tlv.rb +17 -0
  216. data/lib/rex/post/meterpreter/extensions/mimikatz/mimikatz.rb +128 -0
  217. data/lib/rex/post/meterpreter/extensions/mimikatz/tlv.rb +16 -0
  218. data/lib/rex/post/meterpreter/extensions/networkpug/networkpug.rb +57 -0
  219. data/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb +16 -0
  220. data/lib/rex/post/meterpreter/extensions/priv/fs.rb +118 -0
  221. data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +61 -0
  222. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +109 -0
  223. data/lib/rex/post/meterpreter/extensions/priv/tlv.rb +29 -0
  224. data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +117 -0
  225. data/lib/rex/post/meterpreter/extensions/sniffer/tlv.rb +27 -0
  226. data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +396 -0
  227. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +284 -0
  228. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +399 -0
  229. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +104 -0
  230. data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +48 -0
  231. data/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb +59 -0
  232. data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +256 -0
  233. data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +129 -0
  234. data/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb +97 -0
  235. data/lib/rex/post/meterpreter/extensions/stdapi/net/resolve.rb +106 -0
  236. data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +67 -0
  237. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +139 -0
  238. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +180 -0
  239. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +168 -0
  240. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +209 -0
  241. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +38146 -0
  242. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +48 -0
  243. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +2102 -0
  244. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_crypt32.rb +32 -0
  245. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_iphlpapi.rb +97 -0
  246. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3852 -0
  247. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +100 -0
  248. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ntdll.rb +168 -0
  249. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_psapi.rb +32 -0
  250. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_shell32.rb +32 -0
  251. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb +3170 -0
  252. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_version.rb +41 -0
  253. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wlanapi.rb +87 -0
  254. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wldap32.rb +128 -0
  255. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb +613 -0
  256. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +388 -0
  257. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +111 -0
  258. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +149 -0
  259. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb +27 -0
  260. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb +515 -0
  261. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +319 -0
  262. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/platform_util.rb +23 -0
  263. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +301 -0
  264. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb +56 -0
  265. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb +106 -0
  266. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +676 -0
  267. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +96 -0
  268. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +151 -0
  269. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +128 -0
  270. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +192 -0
  271. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +41 -0
  272. data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +60 -0
  273. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +408 -0
  274. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +129 -0
  275. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +55 -0
  276. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +336 -0
  277. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +141 -0
  278. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +328 -0
  279. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +193 -0
  280. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +102 -0
  281. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +188 -0
  282. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +180 -0
  283. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +236 -0
  284. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +259 -0
  285. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +201 -0
  286. data/lib/rex/post/meterpreter/inbound_packet_handler.rb +30 -0
  287. data/lib/rex/post/meterpreter/object_aliases.rb +83 -0
  288. data/lib/rex/post/meterpreter/packet.rb +709 -0
  289. data/lib/rex/post/meterpreter/packet_dispatcher.rb +543 -0
  290. data/lib/rex/post/meterpreter/packet_parser.rb +94 -0
  291. data/lib/rex/post/meterpreter/packet_response_waiter.rb +83 -0
  292. data/lib/rex/post/meterpreter/ui/console.rb +142 -0
  293. data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +86 -0
  294. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +383 -0
  295. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +939 -0
  296. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +109 -0
  297. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb +65 -0
  298. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +198 -0
  299. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard.rb +444 -0
  300. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb +199 -0
  301. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb +118 -0
  302. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb +108 -0
  303. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +242 -0
  304. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +509 -0
  305. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks.rb +60 -0
  306. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +254 -0
  307. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/tftp.rb +159 -0
  308. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +182 -0
  309. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +232 -0
  310. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +62 -0
  311. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +97 -0
  312. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +52 -0
  313. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +133 -0
  314. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +204 -0
  315. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +66 -0
  316. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +527 -0
  317. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +448 -0
  318. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +906 -0
  319. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +318 -0
  320. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +343 -0
  321. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +99 -0
  322. data/lib/rex/post/permission.rb +26 -0
  323. data/lib/rex/post/process.rb +57 -0
  324. data/lib/rex/post/thread.rb +57 -0
  325. data/lib/rex/post/ui.rb +52 -0
  326. data/lib/rex/proto.rb +15 -0
  327. data/lib/rex/proto/addp.rb +218 -0
  328. data/lib/rex/proto/dcerpc.rb +7 -0
  329. data/lib/rex/proto/dcerpc/client.rb +362 -0
  330. data/lib/rex/proto/dcerpc/exceptions.rb +151 -0
  331. data/lib/rex/proto/dcerpc/handle.rb +48 -0
  332. data/lib/rex/proto/dcerpc/ndr.rb +73 -0
  333. data/lib/rex/proto/dcerpc/packet.rb +264 -0
  334. data/lib/rex/proto/dcerpc/response.rb +188 -0
  335. data/lib/rex/proto/dcerpc/uuid.rb +85 -0
  336. data/lib/rex/proto/dcerpc/wdscp.rb +3 -0
  337. data/lib/rex/proto/dcerpc/wdscp/constants.rb +89 -0
  338. data/lib/rex/proto/dcerpc/wdscp/packet.rb +94 -0
  339. data/lib/rex/proto/dhcp.rb +7 -0
  340. data/lib/rex/proto/dhcp/constants.rb +34 -0
  341. data/lib/rex/proto/dhcp/server.rb +334 -0
  342. data/lib/rex/proto/drda.rb +6 -0
  343. data/lib/rex/proto/drda/constants.rb +50 -0
  344. data/lib/rex/proto/drda/packet.rb +253 -0
  345. data/lib/rex/proto/drda/utils.rb +124 -0
  346. data/lib/rex/proto/http.rb +7 -0
  347. data/lib/rex/proto/http/client.rb +722 -0
  348. data/lib/rex/proto/http/client_request.rb +472 -0
  349. data/lib/rex/proto/http/handler.rb +47 -0
  350. data/lib/rex/proto/http/handler/erb.rb +129 -0
  351. data/lib/rex/proto/http/handler/proc.rb +61 -0
  352. data/lib/rex/proto/http/header.rb +173 -0
  353. data/lib/rex/proto/http/packet.rb +414 -0
  354. data/lib/rex/proto/http/request.rb +354 -0
  355. data/lib/rex/proto/http/response.rb +151 -0
  356. data/lib/rex/proto/http/server.rb +385 -0
  357. data/lib/rex/proto/iax2.rb +2 -0
  358. data/lib/rex/proto/iax2/call.rb +326 -0
  359. data/lib/rex/proto/iax2/client.rb +218 -0
  360. data/lib/rex/proto/iax2/codecs.rb +5 -0
  361. data/lib/rex/proto/iax2/codecs/alaw.rb +16 -0
  362. data/lib/rex/proto/iax2/codecs/g711.rb +2176 -0
  363. data/lib/rex/proto/iax2/codecs/mulaw.rb +17 -0
  364. data/lib/rex/proto/iax2/constants.rb +262 -0
  365. data/lib/rex/proto/ipmi.rb +57 -0
  366. data/lib/rex/proto/ipmi/channel_auth_reply.rb +89 -0
  367. data/lib/rex/proto/ipmi/open_session_reply.rb +36 -0
  368. data/lib/rex/proto/ipmi/rakp2.rb +36 -0
  369. data/lib/rex/proto/ipmi/utils.rb +125 -0
  370. data/lib/rex/proto/natpmp.rb +7 -0
  371. data/lib/rex/proto/natpmp/constants.rb +19 -0
  372. data/lib/rex/proto/natpmp/packet.rb +45 -0
  373. data/lib/rex/proto/ntlm.rb +8 -0
  374. data/lib/rex/proto/ntlm/base.rb +327 -0
  375. data/lib/rex/proto/ntlm/constants.rb +75 -0
  376. data/lib/rex/proto/ntlm/crypt.rb +412 -0
  377. data/lib/rex/proto/ntlm/exceptions.rb +17 -0
  378. data/lib/rex/proto/ntlm/message.rb +534 -0
  379. data/lib/rex/proto/ntlm/utils.rb +765 -0
  380. data/lib/rex/proto/ntp.rb +3 -0
  381. data/lib/rex/proto/ntp/constants.rb +12 -0
  382. data/lib/rex/proto/ntp/modes.rb +130 -0
  383. data/lib/rex/proto/pjl.rb +31 -0
  384. data/lib/rex/proto/pjl/client.rb +163 -0
  385. data/lib/rex/proto/proxy/socks4a.rb +441 -0
  386. data/lib/rex/proto/rfb.rb +13 -0
  387. data/lib/rex/proto/rfb/cipher.rb +82 -0
  388. data/lib/rex/proto/rfb/client.rb +205 -0
  389. data/lib/rex/proto/rfb/constants.rb +50 -0
  390. data/lib/rex/proto/sip.rb +4 -0
  391. data/lib/rex/proto/sip/response.rb +61 -0
  392. data/lib/rex/proto/smb.rb +8 -0
  393. data/lib/rex/proto/smb/client.rb +2064 -0
  394. data/lib/rex/proto/smb/constants.rb +1064 -0
  395. data/lib/rex/proto/smb/crypt.rb +37 -0
  396. data/lib/rex/proto/smb/evasions.rb +67 -0
  397. data/lib/rex/proto/smb/exceptions.rb +867 -0
  398. data/lib/rex/proto/smb/simpleclient.rb +173 -0
  399. data/lib/rex/proto/smb/simpleclient/open_file.rb +106 -0
  400. data/lib/rex/proto/smb/simpleclient/open_pipe.rb +57 -0
  401. data/lib/rex/proto/smb/utils.rb +104 -0
  402. data/lib/rex/proto/sunrpc.rb +2 -0
  403. data/lib/rex/proto/sunrpc/client.rb +196 -0
  404. data/lib/rex/proto/tftp.rb +13 -0
  405. data/lib/rex/proto/tftp/client.rb +344 -0
  406. data/lib/rex/proto/tftp/constants.rb +39 -0
  407. data/lib/rex/proto/tftp/server.rb +497 -0
  408. data/lib/rex/random_identifier_generator.rb +177 -0
  409. data/lib/rex/registry.rb +14 -0
  410. data/lib/rex/registry/hive.rb +132 -0
  411. data/lib/rex/registry/lfkey.rb +51 -0
  412. data/lib/rex/registry/nodekey.rb +54 -0
  413. data/lib/rex/registry/regf.rb +25 -0
  414. data/lib/rex/registry/valuekey.rb +67 -0
  415. data/lib/rex/registry/valuelist.rb +29 -0
  416. data/lib/rex/ropbuilder.rb +8 -0
  417. data/lib/rex/ropbuilder/rop.rb +271 -0
  418. data/lib/rex/script.rb +42 -0
  419. data/lib/rex/script/base.rb +61 -0
  420. data/lib/rex/script/meterpreter.rb +16 -0
  421. data/lib/rex/script/shell.rb +10 -0
  422. data/lib/rex/service.rb +49 -0
  423. data/lib/rex/service_manager.rb +154 -0
  424. data/lib/rex/services/local_relay.rb +424 -0
  425. data/lib/rex/socket.rb +788 -0
  426. data/lib/rex/socket/comm.rb +120 -0
  427. data/lib/rex/socket/comm/local.rb +526 -0
  428. data/lib/rex/socket/ip.rb +132 -0
  429. data/lib/rex/socket/parameters.rb +363 -0
  430. data/lib/rex/socket/range_walker.rb +470 -0
  431. data/lib/rex/socket/ssl_tcp.rb +345 -0
  432. data/lib/rex/socket/ssl_tcp_server.rb +188 -0
  433. data/lib/rex/socket/subnet_walker.rb +76 -0
  434. data/lib/rex/socket/switch_board.rb +289 -0
  435. data/lib/rex/socket/tcp.rb +79 -0
  436. data/lib/rex/socket/tcp_server.rb +67 -0
  437. data/lib/rex/socket/udp.rb +165 -0
  438. data/lib/rex/sslscan/result.rb +201 -0
  439. data/lib/rex/sslscan/scanner.rb +206 -0
  440. data/lib/rex/struct2.rb +5 -0
  441. data/lib/rex/struct2/c_struct.rb +181 -0
  442. data/lib/rex/struct2/c_struct_template.rb +39 -0
  443. data/lib/rex/struct2/constant.rb +26 -0
  444. data/lib/rex/struct2/element.rb +44 -0
  445. data/lib/rex/struct2/generic.rb +73 -0
  446. data/lib/rex/struct2/restraint.rb +54 -0
  447. data/lib/rex/struct2/s_string.rb +72 -0
  448. data/lib/rex/struct2/s_struct.rb +111 -0
  449. data/lib/rex/sync.rb +6 -0
  450. data/lib/rex/sync/event.rb +85 -0
  451. data/lib/rex/sync/read_write_lock.rb +177 -0
  452. data/lib/rex/sync/ref.rb +58 -0
  453. data/lib/rex/sync/thread_safe.rb +83 -0
  454. data/lib/rex/text.rb +1813 -0
  455. data/lib/rex/thread_factory.rb +43 -0
  456. data/lib/rex/time.rb +66 -0
  457. data/lib/rex/transformer.rb +116 -0
  458. data/lib/rex/ui.rb +22 -0
  459. data/lib/rex/ui/interactive.rb +304 -0
  460. data/lib/rex/ui/output.rb +85 -0
  461. data/lib/rex/ui/output/none.rb +19 -0
  462. data/lib/rex/ui/progress_tracker.rb +97 -0
  463. data/lib/rex/ui/subscriber.rb +160 -0
  464. data/lib/rex/ui/text/color.rb +98 -0
  465. data/lib/rex/ui/text/dispatcher_shell.rb +538 -0
  466. data/lib/rex/ui/text/input.rb +119 -0
  467. data/lib/rex/ui/text/input/buffer.rb +79 -0
  468. data/lib/rex/ui/text/input/readline.rb +129 -0
  469. data/lib/rex/ui/text/input/socket.rb +96 -0
  470. data/lib/rex/ui/text/input/stdio.rb +46 -0
  471. data/lib/rex/ui/text/irb_shell.rb +62 -0
  472. data/lib/rex/ui/text/output.rb +86 -0
  473. data/lib/rex/ui/text/output/buffer.rb +62 -0
  474. data/lib/rex/ui/text/output/buffer/stdout.rb +26 -0
  475. data/lib/rex/ui/text/output/file.rb +44 -0
  476. data/lib/rex/ui/text/output/socket.rb +44 -0
  477. data/lib/rex/ui/text/output/stdio.rb +53 -0
  478. data/lib/rex/ui/text/output/tee.rb +56 -0
  479. data/lib/rex/ui/text/progress_tracker.rb +57 -0
  480. data/lib/rex/ui/text/shell.rb +403 -0
  481. data/lib/rex/ui/text/table.rb +346 -0
  482. data/lib/rex/zip.rb +96 -0
  483. data/lib/rex/zip/archive.rb +130 -0
  484. data/lib/rex/zip/blocks.rb +184 -0
  485. data/lib/rex/zip/entry.rb +122 -0
  486. data/lib/rex/zip/jar.rb +283 -0
  487. data/lib/rex/zip/samples/comment.rb +32 -0
  488. data/lib/rex/zip/samples/mkwar.rb +138 -0
  489. data/lib/rex/zip/samples/mkzip.rb +19 -0
  490. data/lib/rex/zip/samples/recursive.rb +58 -0
  491. metadata +536 -0
@@ -0,0 +1,13 @@
1
+ # -*- coding: binary -*-
2
+ #
3
+ # RFB protocol support
4
+ #
5
+ # @author Joshua J. Drake <jduck>
6
+ #
7
+ # Based on:
8
+ # vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
9
+ # vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
10
+
11
+ require 'rex/proto/rfb/constants'
12
+ require 'rex/proto/rfb/cipher'
13
+ require 'rex/proto/rfb/client'
@@ -0,0 +1,82 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ #
5
+ # RFB protocol support
6
+ #
7
+ # by Joshua J. Drake <jduck>
8
+ #
9
+ # Based on:
10
+ # vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
11
+ # vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
12
+ #
13
+ ##
14
+
15
+ # Required for VNC authentication
16
+ require 'openssl'
17
+
18
+ module Rex
19
+ module Proto
20
+ module RFB
21
+
22
+ ##
23
+ # A bit of information about the DES algorithm was found here:
24
+ # http://www.vidarholen.net/contents/junk/vnc.html
25
+ #
26
+ # In addition, VNC uses two individual 8 byte block encryptions rather than
27
+ # using any block mode (like cbc, ecb, etc).
28
+ ##
29
+
30
+ class Cipher
31
+
32
+ def self.mangle_password(password)
33
+ key = ''
34
+ key = password.dup if password
35
+ key.slice!(8,key.length) if key.length > 8
36
+ key << "\x00" * (8 - key.length) if key.length < 8
37
+
38
+ # We have to mangle the key so the LSB are kept vs the MSB
39
+ [key.unpack('B*').first.scan(/.{8}/).map! { |e| e.reverse }.join].pack('B*')
40
+ end
41
+
42
+ def self.encrypt(plain, password)
43
+ key = self.mangle_password(password)
44
+
45
+ # pad the plain to 16 chars
46
+ plain << ("\x00" * (16 - plain.length)) if plain.length < 16
47
+
48
+ # VNC auth does two 8-byte blocks individually instead supporting some block mode
49
+ cipher = ''
50
+ 2.times { |x|
51
+ c = OpenSSL::Cipher::Cipher.new('des')
52
+ c.encrypt
53
+ c.key = key
54
+ cipher << c.update(plain[x*8, 8])
55
+ }
56
+
57
+ cipher
58
+ end
59
+
60
+ #
61
+ # NOTE: The default password is that of winvnc/etc which is used for
62
+ # encrypting the password(s) on disk/in registry.
63
+ #
64
+ def self.decrypt(cipher, password = "\x17\x52\x6b\x06\x23\x4e\x58\x07")
65
+ key = self.mangle_password(password)
66
+
67
+ # pad the cipher text to 9 bytes
68
+ cipher << ("\x00" * (9 - cipher.length)) if cipher.length < 9
69
+
70
+ # NOTE: This only does one 8 byte block
71
+ plain = ''
72
+ c = OpenSSL::Cipher::Cipher.new('des')
73
+ c.decrypt
74
+ c.key = key
75
+ c.update(cipher)
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,205 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ #
5
+ # RFB protocol support
6
+ #
7
+ # by Joshua J. Drake <jduck>
8
+ #
9
+ # Based on:
10
+ # vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
11
+ # vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
12
+ #
13
+ # TODO: determine how to detect a view-only session.
14
+ ##
15
+
16
+ module Rex
17
+ module Proto
18
+ module RFB
19
+
20
+ class Client
21
+
22
+ def initialize(sock, opts = {})
23
+ @sock = sock
24
+ @opts = opts
25
+
26
+ @banner = nil
27
+ @majver = MajorVersion
28
+ @minver = -1
29
+ @auth_types = []
30
+ end
31
+
32
+ def read_error_message
33
+ len = @sock.get_once(4)
34
+ return 'Unknown error' if not len or len.length != 4
35
+
36
+ len = len.unpack("N").first
37
+ @sock.get_once(len)
38
+ end
39
+
40
+ def handshake
41
+ @banner = @sock.get_once(12)
42
+ if not @banner
43
+ @error = "Unable to obtain banner from server"
44
+ return false
45
+ end
46
+
47
+ # RFB Protocol Version 3.3 (1998-01)
48
+ # RFB Protocol Version 3.7 (2003-08)
49
+ # RFB Protocol Version 3.8 (2007-06)
50
+
51
+ if @banner =~ /RFB ([0-9]{3})\.([0-9]{3})/
52
+ maj = $1.to_i
53
+ if maj != MajorVersion
54
+ @error = "Invalid major version number: #{maj}"
55
+ return false
56
+ end
57
+ else
58
+ @error = "Invalid RFB banner: #{@banner}"
59
+ return false
60
+ end
61
+
62
+ @minver = $2.to_i
63
+
64
+ our_ver = "RFB %03d.%03d\n" % [MajorVersion, @minver]
65
+ @sock.put(our_ver)
66
+
67
+ true
68
+ end
69
+
70
+ def connect(password = nil)
71
+ return false if not handshake
72
+ return false if not authenticate(password)
73
+ return false if not send_client_init
74
+ true
75
+ end
76
+
77
+ def send_client_init
78
+ if @opts[:exclusive]
79
+ @sock.put("\x00") # do share.
80
+ else
81
+ @sock.put("\x01") # do share.
82
+ end
83
+ end
84
+
85
+ def authenticate(password = nil)
86
+ type = negotiate_authentication
87
+ return false if not type
88
+
89
+ # Authenticate.
90
+ case type
91
+ when AuthType::None
92
+ # Nothing here.
93
+
94
+ when AuthType::VNC
95
+ return false if not negotiate_vnc_auth(password)
96
+
97
+ end
98
+
99
+ # Handle reading the security result message
100
+ result = @sock.get_once(4)
101
+ if not result
102
+ @error = "Unable to read auth result"
103
+ return false
104
+ end
105
+
106
+ result = result.unpack('N').first
107
+ case result
108
+ when 0
109
+ return true
110
+
111
+ when 1
112
+ if @minver >= 8
113
+ msg = read_error_message
114
+ @error = "Authentication failed: #{msg}"
115
+ else
116
+ @error = "Authentication failed"
117
+ end
118
+ when 2
119
+ @error = "Too many authentication attempts"
120
+ else
121
+ @error = "Unknown authentication result: #{result}"
122
+ end
123
+
124
+ false
125
+ end
126
+
127
+ def negotiate_authentication
128
+ # Authentication type negotiation is protocol version specific.
129
+ if @minver < 7
130
+ buf = @sock.get_once(4)
131
+ if not buf
132
+ @error = "Unable to obtain requested authentication method"
133
+ return nil
134
+ end
135
+ @auth_types = buf.unpack('N')
136
+ if not @auth_types or @auth_types.first == 0
137
+ msg = read_error_message
138
+ @error = "No authentication types available: #{msg}"
139
+ return nil
140
+ end
141
+ else
142
+ buf = @sock.get_once(1)
143
+ if not buf
144
+ @error = "Unable to obtain supported authentication method count"
145
+ return nil
146
+ end
147
+
148
+ # first byte is number of security types
149
+ num_types = buf.unpack("C").first
150
+ if (num_types == 0)
151
+ msg = read_error_message
152
+ @error = "No authentication types available: #{msg}"
153
+ return nil
154
+ end
155
+
156
+ buf = @sock.get_once(num_types)
157
+ if not buf or buf.length != num_types
158
+ @error = "Unable to read authentication types"
159
+ return nil
160
+ end
161
+
162
+ @auth_types = buf.unpack("C*")
163
+ end
164
+
165
+ if not @auth_types or @auth_types.length < 1
166
+ @error = "No authentication types found"
167
+ return nil
168
+ end
169
+
170
+ # Select the one we prefer
171
+ selected = nil
172
+ selected ||= AuthType::None if @opts[:allow_none] and @auth_types.include? AuthType::None
173
+ selected ||= AuthType::VNC if @auth_types.include? AuthType::VNC
174
+
175
+ if not selected
176
+ @error = "No supported authentication method found."
177
+ return nil
178
+ end
179
+
180
+ # For 3.7 and later, clients must state which security-type to use
181
+ @sock.put([selected].pack('C')) if @minver >= 7
182
+
183
+ selected
184
+ end
185
+
186
+ def negotiate_vnc_auth(password = nil)
187
+ challenge = @sock.get_once(16)
188
+ if not challenge or challenge.length != 16
189
+ @error = "Unable to obtain VNC challenge"
190
+ return false
191
+ end
192
+
193
+ response = Cipher.encrypt(challenge, password)
194
+ @sock.put(response)
195
+
196
+ true
197
+ end
198
+
199
+ attr_reader :error, :majver, :minver, :auth_types
200
+ attr_reader :view_only
201
+ end
202
+
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,50 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ #
5
+ # RFB protocol support
6
+ #
7
+ # by Joshua J. Drake <jduck>
8
+ #
9
+ # Based on:
10
+ # vnc_auth_none contributed by Matteo Cantoni <goony[at]nothink.org>
11
+ # vnc_auth_login contributed by carstein <carstein.sec[at]gmail.com>
12
+ #
13
+ ##
14
+
15
+ module Rex
16
+ module Proto
17
+ module RFB
18
+
19
+ DefaultPort = 5900
20
+
21
+ # Version information
22
+ MajorVersion = 3
23
+ # NOTE: We will emulate whatever minor version the server reports.
24
+
25
+ # Security types
26
+ class AuthType
27
+ Invalid = 0
28
+ None = 1
29
+ VNC = 2
30
+ RA2 = 5
31
+ RA2ne = 6
32
+ Tight = 16
33
+ Ultra = 17
34
+ TLS = 18
35
+ VeNCrypt = 19
36
+ GtkVncSasl = 20
37
+ MD5Hash = 21
38
+ ColinDeanXVP = 22
39
+
40
+ def self.to_s(num)
41
+ self.constants.each { |c|
42
+ return c.to_s if self.const_get(c) == num
43
+ }
44
+ 'Unknown'
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: binary
2
+
3
+ # SIP protocol support
4
+ require 'rex/proto/sip/response'
@@ -0,0 +1,61 @@
1
+ # encoding: binary
2
+
3
+ module Rex
4
+ module Proto
5
+ # SIP protocol support
6
+ module SIP
7
+ SIP_STATUS_REGEX = /^SIP\/(\d\.\d) (\d{3})\s*(.*)$/
8
+
9
+ # Represents a generic SIP message
10
+ class Message
11
+ attr_accessor :headers
12
+
13
+ def initialize
14
+ @headers = {}
15
+ end
16
+
17
+ # Returns a list of all values from all +name+ headers, regardless of case,
18
+ # or nil if no matching header is found
19
+ def header(name)
20
+ matches = @headers.select { |k, _| k.downcase == name.downcase }
21
+ return nil if matches.empty?
22
+ matches.values.flatten
23
+ end
24
+
25
+ # Returns a hash of header name to values mapping
26
+ # from the provided message, or nil if no headers
27
+ # are found
28
+ def self.extract_headers(message)
29
+ pairs = message.scan(/^([^\s:]+):\s*(.*)$/)
30
+ return nil if pairs.empty?
31
+ headers = {}
32
+ pairs.each do |pair|
33
+ headers[pair.first] ||= []
34
+ headers[pair.first] << pair.last.strip
35
+ end
36
+ headers
37
+ end
38
+ end
39
+
40
+ # Represents a SIP response message
41
+ class Response < Message
42
+ attr_accessor :code, :message, :status_line, :version
43
+
44
+ # Parses +data+, constructs and returns a Response
45
+ def self.parse(data)
46
+ response = Response.new
47
+ # do some basic sanity checking on this response to ensure that it is SIP
48
+ response.status_line = data.split(/\r\n/)[0]
49
+ unless response.status_line && response.status_line =~ SIP_STATUS_REGEX
50
+ fail(ArgumentError, "Invalid SIP status line: #{response.status_line}")
51
+ end
52
+ response.version = Regexp.last_match(1)
53
+ response.code = Regexp.last_match(2)
54
+ response.message = Regexp.last_match(3)
55
+ response.headers = extract_headers(data)
56
+ response
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,8 @@
1
+ # -*- coding: binary -*-
2
+ require 'rex/proto/smb/constants'
3
+ require 'rex/proto/smb/exceptions'
4
+ require 'rex/proto/smb/evasions'
5
+ require 'rex/proto/smb/crypt'
6
+ require 'rex/proto/smb/utils'
7
+ require 'rex/proto/smb/client'
8
+ require 'rex/proto/smb/simpleclient'
@@ -0,0 +1,2064 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module Proto
4
+ module SMB
5
+ class Client
6
+
7
+ require 'rex/text'
8
+ require 'rex/struct2'
9
+ require 'rex/proto/smb/constants'
10
+ require 'rex/proto/smb/exceptions'
11
+ require 'rex/proto/smb/evasions'
12
+ require 'rex/proto/smb/utils'
13
+ require 'rex/proto/smb/crypt'
14
+ require 'rex/proto/ntlm/crypt'
15
+ require 'rex/proto/ntlm/constants'
16
+ require 'rex/proto/ntlm/utils'
17
+
18
+
19
+ # Some short-hand class aliases
20
+ CONST = Rex::Proto::SMB::Constants
21
+ CRYPT = Rex::Proto::SMB::Crypt
22
+ UTILS = Rex::Proto::SMB::Utils
23
+ XCEPT = Rex::Proto::SMB::Exceptions
24
+ EVADE = Rex::Proto::SMB::Evasions
25
+ NTLM_CRYPT = Rex::Proto::NTLM::Crypt
26
+ NTLM_CONST = Rex::Proto::NTLM::Constants
27
+ NTLM_UTILS = Rex::Proto::NTLM::Utils
28
+
29
+ def initialize(socket)
30
+ self.socket = socket
31
+ self.native_os = 'Windows 2000 2195'
32
+ self.native_lm = 'Windows 2000 5.0'
33
+ self.encrypt_passwords = true
34
+ self.extended_security = false
35
+ self.multiplex_id = rand(0xffff)
36
+ self.process_id = rand(0xffff)
37
+ self.read_timeout = 10
38
+ self.evasion_opts = {
39
+
40
+ # Padding is performed between packet headers and data
41
+ 'pad_data' => EVADE::EVASION_NONE,
42
+
43
+ # File path padding is performed on all open/create calls
44
+ 'pad_file' => EVADE::EVASION_NONE,
45
+
46
+ # Modify the \PIPE\ string in trans_named_pipe calls
47
+ 'obscure_trans_pipe' => EVADE::EVASION_NONE,
48
+ }
49
+
50
+ self.verify_signature = false
51
+ self.use_ntlmv2 = false
52
+ self.usentlm2_session = true
53
+ self.send_lm = true
54
+ self.use_lanman_key = false
55
+ self.send_ntlm = true
56
+
57
+ # Signing
58
+ self.sequence_counter = 0
59
+ self.signing_key = ''
60
+ self.require_signing = false
61
+
62
+ #Misc
63
+ self.spnopt = {}
64
+
65
+ end
66
+
67
+ # Read a SMB packet from the socket
68
+ def smb_recv
69
+
70
+ data = socket.timed_read(4, self.read_timeout)
71
+ if (data.nil? or data.length < 4)
72
+ raise XCEPT::NoReply
73
+ end
74
+
75
+ recv_len = data[2,2].unpack('n')[0]
76
+ if (recv_len == 0)
77
+ return data
78
+ end
79
+
80
+ recv_len += 4
81
+
82
+ while (data.length != recv_len)
83
+ buff = ''
84
+
85
+ begin
86
+ buff << self.socket.timed_read(recv_len - data.length, self.read_timeout)
87
+ rescue Timeout::Error
88
+ rescue
89
+ raise XCEPT::ReadPacket
90
+ end
91
+
92
+ if (buff.nil? or buff.length == 0)
93
+ raise XCEPT::ReadPacket
94
+ end
95
+
96
+ data << buff
97
+ end
98
+
99
+ #signing
100
+ if self.require_signing && self.signing_key != ''
101
+ if self.verify_signature
102
+ raise XCEPT::IncorrectSigningError if not CRYPT::is_signature_correct?(self.signing_key,self.sequence_counter,data)
103
+ end
104
+ self.sequence_counter += 1
105
+ end
106
+
107
+ return data
108
+
109
+
110
+ end
111
+
112
+ # Send a SMB packet down the socket
113
+ def smb_send(data, evasion_level=0)
114
+
115
+ # evasion_level is ignored, since real evasion happens
116
+ # in the actual socket layer
117
+
118
+ size = 0
119
+ wait = 0
120
+
121
+ #signing
122
+ if self.require_signing && self.signing_key != ''
123
+ data = CRYPT::sign_smb_packet(self.signing_key, self.sequence_counter, data)
124
+ self.sequence_counter += 1
125
+ end
126
+
127
+ begin
128
+ # Just send the packet and return
129
+ if (size == 0 or size >= data.length)
130
+ return self.socket.put(data)
131
+ end
132
+
133
+ # Break the packet up into chunks and wait between them
134
+ ret = 0
135
+ while ( (chunk = data.slice!(0, size)).length > 0 )
136
+ ret = self.socket.put(chunk)
137
+ if (wait > 0)
138
+ ::IO.select(nil, nil, nil, wait)
139
+ end
140
+ end
141
+ return ret
142
+ end
143
+ end
144
+
145
+ # Set the SMB parameters to some reasonable defaults
146
+ def smb_defaults(packet)
147
+ packet.v['MultiplexID'] = self.multiplex_id.to_i
148
+ packet.v['TreeID'] = self.last_tree_id.to_i
149
+ packet.v['UserID'] = self.auth_user_id.to_i
150
+ packet.v['ProcessID'] = self.process_id.to_i
151
+ end
152
+
153
+ # Receive a full SMB reply and cache the parsed packet
154
+ def smb_recv_and_cache
155
+ @smb_recv_cache ||= []
156
+
157
+ # This will throw an exception if it fails to read the whole packet
158
+ data = self.smb_recv
159
+
160
+ pkt = CONST::SMB_BASE_PKT.make_struct
161
+ pkt.from_s(data)
162
+
163
+ # Store the received packet into the cache
164
+ @smb_recv_cache << [ pkt, data, Time.now ]
165
+ end
166
+
167
+ # Scan the packet receive cache for a matching response
168
+ def smb_recv_cache_find_match(expected_type)
169
+
170
+ clean = []
171
+ found = nil
172
+
173
+ @smb_recv_cache.each do |cent|
174
+ pkt, data, tstamp = cent
175
+
176
+ # Return matching packets and mark for removal
177
+ if pkt['Payload']['SMB'].v['Command'] == expected_type
178
+ found = [pkt,data]
179
+ clean << cent
180
+ end
181
+
182
+ # Purge any packets older than 5 minutes
183
+ if Time.now.to_i - tstamp.to_i > 300
184
+ clean << cent
185
+ end
186
+
187
+ break if found
188
+ end
189
+
190
+ clean.each do |cent|
191
+ @smb_recv_cache.delete(cent)
192
+ end
193
+
194
+ found
195
+ end
196
+
197
+ # The main dispatcher for all incoming SMB packets
198
+ def smb_recv_parse(expected_type, ignore_errors = false)
199
+
200
+ pkt = nil
201
+ data = nil
202
+
203
+ # This allows for some leeway when a previous response has not
204
+ # been processed but a new request was sent. The old response
205
+ # will eventually be timed out of the cache.
206
+ 1.upto(3) do |attempt|
207
+ smb_recv_and_cache
208
+ pkt,data = smb_recv_cache_find_match(expected_type)
209
+ break if pkt
210
+ end
211
+
212
+ begin
213
+ case pkt['Payload']['SMB'].v['Command']
214
+
215
+ when CONST::SMB_COM_NEGOTIATE
216
+ res = smb_parse_negotiate(pkt, data)
217
+
218
+ when CONST::SMB_COM_SESSION_SETUP_ANDX
219
+ res = smb_parse_session_setup(pkt, data)
220
+
221
+ when CONST::SMB_COM_TREE_CONNECT_ANDX
222
+ res = smb_parse_tree_connect(pkt, data)
223
+
224
+ when CONST::SMB_COM_TREE_DISCONNECT
225
+ res = smb_parse_tree_disconnect(pkt, data)
226
+
227
+ when CONST::SMB_COM_NT_CREATE_ANDX
228
+ res = smb_parse_create(pkt, data)
229
+
230
+ when CONST::SMB_COM_TRANSACTION, CONST::SMB_COM_TRANSACTION2
231
+ res = smb_parse_trans(pkt, data)
232
+
233
+ when CONST::SMB_COM_NT_TRANSACT
234
+ res = smb_parse_nttrans(pkt, data)
235
+
236
+ when CONST::SMB_COM_NT_TRANSACT_SECONDARY
237
+ res = smb_parse_nttrans(pkt, data)
238
+
239
+ when CONST::SMB_COM_OPEN_ANDX
240
+ res = smb_parse_open(pkt, data)
241
+
242
+ when CONST::SMB_COM_WRITE_ANDX
243
+ res = smb_parse_write(pkt, data)
244
+
245
+ when CONST::SMB_COM_READ_ANDX
246
+ res = smb_parse_read(pkt, data)
247
+
248
+ when CONST::SMB_COM_CLOSE
249
+ res = smb_parse_close(pkt, data)
250
+
251
+ when CONST::SMB_COM_DELETE
252
+ res = smb_parse_delete(pkt, data)
253
+
254
+ else
255
+ raise XCEPT::InvalidCommand
256
+ end
257
+
258
+ if (ignore_errors == false and pkt['Payload']['SMB'].v['ErrorClass'] != 0)
259
+ raise XCEPT::ErrorCode
260
+ end
261
+
262
+ rescue XCEPT::InvalidWordCount, XCEPT::InvalidCommand, XCEPT::ErrorCode
263
+ $!.word_count = pkt['Payload']['SMB'].v['WordCount']
264
+ $!.command = pkt['Payload']['SMB'].v['Command']
265
+ $!.error_code = pkt['Payload']['SMB'].v['ErrorClass']
266
+ raise $!
267
+ end
268
+
269
+ return res
270
+ end
271
+
272
+ # Process incoming SMB_COM_NEGOTIATE packets
273
+ def smb_parse_negotiate(pkt, data)
274
+ #Process NTLM negotiate responses
275
+ if (pkt['Payload']['SMB'].v['WordCount'] == 17)
276
+ res = CONST::SMB_NEG_RES_NT_PKT.make_struct
277
+ res.from_s(data)
278
+ return res
279
+ end
280
+
281
+ # Process LANMAN negotiate responses
282
+ if (pkt['Payload']['SMB'].v['WordCount'] == 13)
283
+ res = CONST::SMB_NEG_RES_LM_PKT.make_struct
284
+ res.from_s(data)
285
+ return res
286
+ end
287
+
288
+ # Process ERROR negotiate responses
289
+ if (pkt['Payload']['SMB'].v['WordCount'] == 1)
290
+ res = CONST::SMB_NEG_RES_ERR_PKT.make_struct
291
+ res.from_s(data)
292
+ return res
293
+ end
294
+
295
+ # Process SMB error responses
296
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
297
+ return pkt
298
+ end
299
+
300
+ raise XCEPT::InvalidWordCount
301
+ end
302
+
303
+ # Process incoming SMB_COM_SESSION_SETUP_ANDX packets
304
+ def smb_parse_session_setup(pkt, data)
305
+ # Process NTLMSSP negotiate responses
306
+ if (pkt['Payload']['SMB'].v['WordCount'] == 4)
307
+ res = CONST::SMB_SETUP_NTLMV2_RES_PKT.make_struct
308
+ res.from_s(data)
309
+ return res
310
+ end
311
+
312
+ # Process LANMAN responses
313
+ if (pkt['Payload']['SMB'].v['WordCount'] == 3)
314
+ res = CONST::SMB_SETUP_RES_PKT.make_struct
315
+ res.from_s(data)
316
+ return res
317
+ end
318
+
319
+ # Process SMB error responses
320
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
321
+ return pkt
322
+ end
323
+
324
+ raise XCEPT::InvalidWordCount
325
+ end
326
+
327
+ # Process incoming SMB_COM_TREE_CONNECT_ANDX packets
328
+ def smb_parse_tree_connect(pkt, data)
329
+
330
+ if (pkt['Payload']['SMB'].v['WordCount'] == 3)
331
+ res = CONST::SMB_TREE_CONN_RES_PKT.make_struct
332
+ res.from_s(data)
333
+ return res
334
+ end
335
+
336
+ # Process SMB error responses
337
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
338
+ return pkt
339
+ end
340
+
341
+ raise XCEPT::InvalidWordCount
342
+ end
343
+
344
+ # Process incoming SMB_COM_TREE_DISCONNECT packets
345
+ def smb_parse_tree_disconnect(pkt, data)
346
+
347
+ # Process SMB responses
348
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
349
+ res = CONST::SMB_TREE_DISCONN_RES_PKT.make_struct
350
+ res.from_s(data)
351
+ return res
352
+ end
353
+
354
+ raise XCEPT::InvalidWordCount
355
+ end
356
+
357
+ # Process incoming SMB_COM_NT_CREATE_ANDX packets
358
+ def smb_parse_create(pkt, data)
359
+
360
+ # Windows says 42, but Samba says 34, same structure :-/
361
+ if (pkt['Payload']['SMB'].v['WordCount'] == 42)
362
+ res = CONST::SMB_CREATE_RES_PKT.make_struct
363
+ res.from_s(data)
364
+ return res
365
+ end
366
+
367
+ if (pkt['Payload']['SMB'].v['WordCount'] == 34)
368
+ res = CONST::SMB_CREATE_RES_PKT.make_struct
369
+ res.from_s(data)
370
+ return res
371
+ end
372
+
373
+ # Process SMB error responses
374
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
375
+ return pkt
376
+ end
377
+
378
+ raise XCEPT::InvalidWordCount
379
+ end
380
+
381
+ # Process incoming SMB_COM_TRANSACTION packets
382
+ def smb_parse_trans(pkt, data)
383
+
384
+ if (pkt['Payload']['SMB'].v['WordCount'] == 10)
385
+ res = CONST::SMB_TRANS_RES_PKT.make_struct
386
+ res.from_s(data)
387
+ return res
388
+ end
389
+
390
+ # Process SMB error responses
391
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
392
+ return pkt
393
+ end
394
+
395
+ raise XCEPT::InvalidWordCount
396
+ end
397
+
398
+ # Process incoming SMB_COM_NT_TRANSACT packets
399
+ def smb_parse_nttrans(pkt, data)
400
+
401
+ # Process SMB error responses
402
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
403
+ return pkt
404
+ end
405
+
406
+ if (pkt['Payload']['SMB'].v['WordCount'] >= 18)
407
+ res = CONST::SMB_NTTRANS_RES_PKT.make_struct
408
+ res.from_s(data)
409
+ return res
410
+ end
411
+
412
+ raise XCEPT::InvalidWordCount
413
+ end
414
+
415
+ # Process incoming SMB_COM_OPEN_ANDX packets
416
+ def smb_parse_open(pkt, data)
417
+ # Process open responses
418
+ if (pkt['Payload']['SMB'].v['WordCount'] == 15)
419
+ res = CONST::SMB_OPEN_RES_PKT.make_struct
420
+ res.from_s(data)
421
+ return res
422
+ end
423
+
424
+ # Process SMB error responses
425
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
426
+ return pkt
427
+ end
428
+
429
+ raise XCEPT::InvalidWordCount
430
+ end
431
+
432
+ # Process incoming SMB_COM_WRITE_ANDX packets
433
+ def smb_parse_write(pkt, data)
434
+
435
+ # Process write responses
436
+ if (pkt['Payload']['SMB'].v['WordCount'] == 6)
437
+ res = CONST::SMB_WRITE_RES_PKT.make_struct
438
+ res.from_s(data)
439
+ return res
440
+ end
441
+
442
+ # Process SMB error responses
443
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
444
+ return pkt
445
+ end
446
+
447
+ raise XCEPT::InvalidWordCount
448
+ end
449
+
450
+ # Process incoming SMB_COM_READ_ANDX packets
451
+ def smb_parse_read(pkt, data)
452
+
453
+ # Process read responses
454
+ if (pkt['Payload']['SMB'].v['WordCount'] == 12)
455
+ res = CONST::SMB_READ_RES_PKT.make_struct
456
+ res.from_s(data)
457
+ return res
458
+ end
459
+
460
+ # Process SMB error responses
461
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
462
+ return pkt
463
+ end
464
+
465
+ raise XCEPT::InvalidWordCount
466
+ end
467
+
468
+ # Process incoming SMB_COM_CLOSE packets
469
+ def smb_parse_close(pkt, data)
470
+
471
+ # Process SMB error responses
472
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
473
+ return pkt
474
+ end
475
+
476
+ raise XCEPT::InvalidWordCount
477
+ end
478
+
479
+ # Process incoming SMB_COM_DELETE packets
480
+ def smb_parse_delete(pkt, data)
481
+
482
+ # Process SMB error responses
483
+ if (pkt['Payload']['SMB'].v['WordCount'] == 0)
484
+ res = CONST::SMB_DELETE_RES_PKT.make_struct
485
+ res.from_s(data)
486
+ return res
487
+ end
488
+
489
+ raise XCEPT::InvalidWordCount
490
+ end
491
+
492
+ # Request a SMB session over NetBIOS
493
+ def session_request(name = '*SMBSERVER', do_recv = true)
494
+
495
+ name ||= '*SMBSERVER'
496
+
497
+ data = ''
498
+ data << "\x20" + UTILS.nbname_encode(name) + "\x00"
499
+ data << "\x20" + CONST::NETBIOS_REDIR + "\x00"
500
+
501
+ pkt = CONST::NBRAW_PKT.make_struct
502
+ pkt.v['Type'] = 0x81
503
+ pkt['Payload'].v['Payload'] = data
504
+
505
+ # Most SMB implementations can't handle this being fragmented
506
+ ret = self.smb_send(pkt.to_s, EVADE::EVASION_NONE)
507
+ return ret if not do_recv
508
+
509
+ res = self.smb_recv
510
+
511
+ ack = CONST::NBRAW_PKT.make_struct
512
+ ack.from_s(res)
513
+
514
+ if (ack.v['Type'] != 130)
515
+ raise XCEPT::NetbiosSessionFailed
516
+ end
517
+
518
+ return ack
519
+ end
520
+
521
+ # Negotiate a SMB dialect
522
+ def negotiate(smb_extended_security=true, do_recv = true)
523
+
524
+ dialects = ['LANMAN1.0', 'LM1.2X002' ]
525
+
526
+ if (self.encrypt_passwords)
527
+ dialects.push('NT LANMAN 1.0', 'NT LM 0.12')
528
+ end
529
+
530
+ data = dialects.collect { |dialect| "\x02" + dialect + "\x00" }.join('')
531
+
532
+ pkt = CONST::SMB_NEG_PKT.make_struct
533
+ self.smb_defaults(pkt['Payload']['SMB'])
534
+
535
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NEGOTIATE
536
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
537
+
538
+ if(smb_extended_security)
539
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
540
+ else
541
+ pkt['Payload']['SMB'].v['Flags2'] = 0xc001
542
+ end
543
+
544
+ pkt['Payload'].v['Payload'] = data
545
+
546
+ ret = self.smb_send(pkt.to_s, EVADE::EVASION_NONE)
547
+ return ret if not do_recv
548
+
549
+ ack = self.smb_recv_parse(CONST::SMB_COM_NEGOTIATE)
550
+
551
+ idx = ack['Payload'].v['Dialect']
552
+
553
+ # Check for failed dialect selection
554
+ if (idx < 0 or idx >= dialects.length)
555
+ return nil
556
+ end
557
+
558
+ # Set the selected dialect
559
+ self.dialect = dialects[idx]
560
+
561
+ # Does the server support extended security negotiation?
562
+ if (ack['Payload'].v['Capabilities'] & 0x80000000 != 0)
563
+ self.extended_security = true
564
+ end
565
+
566
+ # Set the security mode
567
+ self.security_mode = ack['Payload'].v['SecurityMode']
568
+
569
+ #set require_signing
570
+ if (ack['Payload'].v['SecurityMode'] & 0x08 != 0)
571
+ self.require_signing = true
572
+ end
573
+
574
+ # Set the challenge key
575
+ if (ack['Payload'].v['EncryptionKey'] != nil)
576
+ self.challenge_key = ack['Payload'].v['EncryptionKey']
577
+ else
578
+ # Handle Windows NT 4.0 responses
579
+ if (ack['Payload'].v['KeyLength'] > 0)
580
+ self.challenge_key = ack['Payload'].v['Payload'][0, ack['Payload'].v['KeyLength']]
581
+ end
582
+ end
583
+
584
+ # Set the session identifier
585
+ if (ack['Payload'].v['SessionKey'] != nil)
586
+ self.session_id = ack['Payload'].v['SessionKey']
587
+ end
588
+
589
+ # Extract the payload (GUID/SecurityBlob)
590
+ buf = ack['Payload'].v['Payload'] || ''
591
+
592
+ # Set the server GUID
593
+ if (self.extended_security and buf.length >= 16)
594
+ self.server_guid = buf[0,16]
595
+ end
596
+
597
+ # Set the server SecurityBlob
598
+ if (self.extended_security and buf.length > 16)
599
+ # buf[16, buf.length - 16]
600
+ end
601
+
602
+ # The number of 100-nanosecond intervals that have elapsed since January 1, 1601, in
603
+ # Coordinated Universal Time (UTC) format.
604
+ # We convert it to a friendly Time object here
605
+ self.system_time = UTILS.time_smb_to_unix(ack['Payload'].v['SystemTimeHigh'],ack['Payload'].v['SystemTimeLow'])
606
+ self.system_time = ::Time.at( self.system_time )
607
+
608
+ # A signed 16-bit signed integer that represents the server's time zone, in minutes,
609
+ # from UTC. The time zone of the server MUST be expressed in minutes, plus or minus,
610
+ # from UTC.
611
+ # NOTE: althought the spec says +/- it doesn't say that it should be inverted :-/
612
+ system_zone = ack['Payload'].v['ServerTimeZone']
613
+ # Convert the ServerTimeZone to _seconds_ and back into a signed integer :-/
614
+ if (system_zone & 0x8000) == 0x8000
615
+ system_zone = (( (~system_zone) & 0x0FFF ) + 1 )
616
+ else
617
+ system_zone *= -1
618
+ end
619
+ self.system_zone = system_zone * 60
620
+
621
+ return ack
622
+ end
623
+
624
+
625
+ # Authenticate and establish a session
626
+ def session_setup(*args)
627
+
628
+ if (self.dialect =~ /^(NT LANMAN 1.0|NT LM 0.12)$/)
629
+
630
+ if (self.challenge_key)
631
+ return self.session_setup_no_ntlmssp(*args)
632
+ end
633
+
634
+ if ( self.extended_security )
635
+ return self.session_setup_with_ntlmssp(*args)
636
+ end
637
+
638
+ end
639
+
640
+ return self.session_setup_clear(*args)
641
+ end
642
+
643
+ # Authenticate using clear-text passwords
644
+ def session_setup_clear(user = '', pass = '', domain = '', do_recv = true)
645
+
646
+ data = [ pass, user, domain, self.native_os, self.native_lm ].collect{ |a| a + "\x00" }.join('');
647
+
648
+ pkt = CONST::SMB_SETUP_LANMAN_PKT.make_struct
649
+ self.smb_defaults(pkt['Payload']['SMB'])
650
+
651
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
652
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
653
+ if self.require_signing
654
+ #ascii
655
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
656
+ else
657
+ #ascii
658
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
659
+ end
660
+
661
+ pkt['Payload']['SMB'].v['WordCount'] = 10
662
+ pkt['Payload'].v['AndX'] = 255
663
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
664
+ pkt['Payload'].v['MaxMPX'] = 2
665
+ pkt['Payload'].v['VCNum'] = 1
666
+ pkt['Payload'].v['PasswordLen'] = pass.length + 1
667
+ pkt['Payload'].v['Capabilities'] = 64
668
+ pkt['Payload'].v['SessionKey'] = self.session_id
669
+ pkt['Payload'].v['Payload'] = data
670
+
671
+ ret = self.smb_send(pkt.to_s)
672
+ return ret if not do_recv
673
+
674
+ ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
675
+
676
+ if (ack['Payload'].v['Action'] != 1 and user.length > 0)
677
+ self.auth_user = user
678
+ end
679
+
680
+ self.auth_user_id = ack['Payload']['SMB'].v['UserID']
681
+
682
+ info = ack['Payload'].v['Payload'].split(/\x00/n)
683
+ self.peer_native_os = info[0]
684
+ self.peer_native_lm = info[1]
685
+ self.default_domain = info[2]
686
+
687
+ return ack
688
+ end
689
+
690
+ # Authenticate without NTLMSSP
691
+ def session_setup_no_ntlmssp(user = '', pass = '', domain = '', do_recv = true)
692
+
693
+ # Requires a challenge key to have been seen during negotiation
694
+ raise XCEPT::NTLM1MissingChallenge if not self.challenge_key
695
+
696
+ #
697
+ # We can not yet handle signing in this situation
698
+ # But instead of throwing an exception,we will disable signing, continue and hope for the best.
699
+ #
700
+
701
+ #raise XCEPT::SigningError if self.require_signing
702
+ self.require_signing = false if self.require_signing
703
+
704
+
705
+ if NTLM_UTILS.is_pass_ntlm_hash?(pass)
706
+ arglm = {
707
+ :lm_hash => [ pass.upcase()[0,32] ].pack('H32'),
708
+ :challenge => self.challenge_key
709
+ }
710
+ hash_lm = NTLM_CRYPT::lm_response(arglm)
711
+
712
+ argntlm = {
713
+ :ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
714
+ :challenge => self.challenge_key
715
+ }
716
+ hash_nt = NTLM_CRYPT::ntlm_response(argntlm)
717
+ else
718
+ hash_lm = pass.length > 0 ? NTLM_CRYPT.lanman_des(pass, self.challenge_key) : ''
719
+ hash_nt = pass.length > 0 ? NTLM_CRYPT.ntlm_md4(pass, self.challenge_key) : ''
720
+ end
721
+
722
+ data = ''
723
+ data << hash_lm
724
+ data << hash_nt
725
+ data << user + "\x00"
726
+ data << domain + "\x00"
727
+ data << self.native_os + "\x00"
728
+ data << self.native_lm + "\x00"
729
+
730
+ pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
731
+ self.smb_defaults(pkt['Payload']['SMB'])
732
+
733
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
734
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
735
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2001
736
+ pkt['Payload']['SMB'].v['WordCount'] = 13
737
+ pkt['Payload'].v['AndX'] = 255
738
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
739
+ pkt['Payload'].v['MaxMPX'] = 2
740
+ pkt['Payload'].v['VCNum'] = 1
741
+ pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
742
+ pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
743
+ pkt['Payload'].v['Capabilities'] = 64
744
+ pkt['Payload'].v['SessionKey'] = self.session_id
745
+ pkt['Payload'].v['Payload'] = data
746
+
747
+ ret = self.smb_send(pkt.to_s)
748
+ return ret if not do_recv
749
+
750
+ ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
751
+
752
+ if (ack['Payload'].v['Action'] != 1 and user.length > 0)
753
+ self.auth_user = user
754
+ end
755
+
756
+ self.auth_user_id = ack['Payload']['SMB'].v['UserID']
757
+
758
+ info = ack['Payload'].v['Payload'].split(/\x00/n)
759
+
760
+ self.peer_native_os = info[0]
761
+ self.peer_native_lm = info[1]
762
+ self.default_domain = info[2]
763
+
764
+ return ack
765
+ end
766
+
767
+
768
+ # Authenticate without ntlmssp with a precomputed hash pair
769
+ def session_setup_no_ntlmssp_prehash(user, domain, hash_lm, hash_nt, do_recv = true)
770
+
771
+ data = ''
772
+ data << hash_lm
773
+ data << hash_nt
774
+ data << user + "\x00"
775
+ data << domain + "\x00"
776
+ data << self.native_os + "\x00"
777
+ data << self.native_lm + "\x00"
778
+
779
+ pkt = CONST::SMB_SETUP_NTLMV1_PKT.make_struct
780
+ self.smb_defaults(pkt['Payload']['SMB'])
781
+
782
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
783
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
784
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2001
785
+ pkt['Payload']['SMB'].v['WordCount'] = 13
786
+ pkt['Payload'].v['AndX'] = 255
787
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
788
+ pkt['Payload'].v['MaxMPX'] = 2
789
+ pkt['Payload'].v['VCNum'] = 1
790
+ pkt['Payload'].v['PasswordLenLM'] = hash_lm.length
791
+ pkt['Payload'].v['PasswordLenNT'] = hash_nt.length
792
+ pkt['Payload'].v['Capabilities'] = 64
793
+ pkt['Payload'].v['SessionKey'] = self.session_id
794
+ pkt['Payload'].v['Payload'] = data
795
+
796
+ ret = self.smb_send(pkt.to_s)
797
+ return ret if not do_recv
798
+
799
+ ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX)
800
+
801
+ if (ack['Payload'].v['Action'] != 1 and user.length > 0)
802
+ self.auth_user = user
803
+ end
804
+
805
+ self.auth_user_id = ack['Payload']['SMB'].v['UserID']
806
+
807
+ info = ack['Payload'].v['Payload'].split(/\x00/n)
808
+
809
+ self.peer_native_os = info[0]
810
+ self.peer_native_lm = info[1]
811
+ self.default_domain = info[2]
812
+
813
+ return ack
814
+ end
815
+
816
+ # Authenticate using extended security negotiation
817
+ def session_setup_with_ntlmssp(user = '', pass = '', domain = '', name = nil, do_recv = true)
818
+
819
+ ntlm_options = {
820
+ :signing => self.require_signing,
821
+ :usentlm2_session => self.usentlm2_session,
822
+ :use_ntlmv2 => self.use_ntlmv2,
823
+ :send_lm => self.send_lm,
824
+ :send_ntlm => self.send_ntlm,
825
+ :use_lanman_key => self.use_lanman_key
826
+ }
827
+
828
+ ntlmssp_flags = NTLM_UTILS.make_ntlm_flags(ntlm_options)
829
+
830
+ if (name == nil)
831
+ name = Rex::Text.rand_text_alphanumeric(16)
832
+ end
833
+
834
+ blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name, ntlmssp_flags)
835
+
836
+ native_data = ''
837
+ native_data << self.native_os + "\x00"
838
+ native_data << self.native_lm + "\x00"
839
+
840
+ pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
841
+ self.smb_defaults(pkt['Payload']['SMB'])
842
+
843
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
844
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
845
+ if require_signing
846
+ #ascii
847
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
848
+ else
849
+ #ascii
850
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
851
+ end
852
+ pkt['Payload']['SMB'].v['WordCount'] = 12
853
+ pkt['Payload'].v['AndX'] = 255
854
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
855
+ pkt['Payload'].v['MaxMPX'] = 2
856
+ pkt['Payload'].v['VCNum'] = 1
857
+ pkt['Payload'].v['SecurityBlobLen'] = blob.length
858
+ pkt['Payload'].v['Capabilities'] = 0x800000d4
859
+ pkt['Payload'].v['SessionKey'] = self.session_id
860
+ pkt['Payload'].v['Payload'] = blob + native_data
861
+
862
+ ret = self.smb_send(pkt.to_s)
863
+
864
+ return ret if not do_recv
865
+
866
+ ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
867
+
868
+
869
+ # The server doesn't know about NTLM_NEGOTIATE
870
+ if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
871
+ return session_setup_no_ntlmssp(user, pass, domain)
872
+ end
873
+
874
+ # Make sure the error code tells us to continue processing
875
+ if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016)
876
+ failure = XCEPT::ErrorCode.new
877
+ failure.word_count = ack['Payload']['SMB'].v['WordCount']
878
+ failure.command = ack['Payload']['SMB'].v['Command']
879
+ failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
880
+ raise failure
881
+ end
882
+
883
+ # Extract the SecurityBlob from the response
884
+ data = ack['Payload'].v['Payload']
885
+ blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
886
+
887
+ # Extract the native lanman and os strings
888
+ info = data.split(/\x00/n)
889
+ self.peer_native_os = info[0]
890
+ self.peer_native_lm = info[1]
891
+
892
+ # Save the temporary UserID for use in the next request
893
+ temp_user_id = ack['Payload']['SMB'].v['UserID']
894
+
895
+ # Get default data
896
+ blob_data = NTLM_UTILS.parse_ntlm_type_2_blob(blob)
897
+ self.challenge_key = blob_data[:challenge_key]
898
+ server_ntlmssp_flags = blob_data[:server_ntlmssp_flags] #else should raise an error
899
+ #netbios name
900
+ self.default_name = blob_data[:default_name] || ''
901
+ #netbios domain
902
+ self.default_domain = blob_data[:default_domain] || ''
903
+ #dns name
904
+ self.dns_host_name = blob_data[:dns_host_name] || ''
905
+ #dns domain
906
+ self.dns_domain_name = blob_data[:dns_domain_name] || ''
907
+ #Client time
908
+ chall_MsvAvTimestamp = blob_data[:chall_MsvAvTimestamp] || ''
909
+
910
+
911
+ resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge = NTLM_UTILS.create_lm_ntlm_responses(user, pass, self.challenge_key, domain,
912
+ default_name, default_domain, dns_host_name,
913
+ dns_domain_name, chall_MsvAvTimestamp ,
914
+ self.spnopt, ntlm_options)
915
+ enc_session_key = ''
916
+ self.sequence_counter = 0
917
+
918
+ if self.require_signing
919
+ self.signing_key, enc_session_key, ntlmssp_flags = NTLM_UTILS.create_session_key(ntlmssp_flags, server_ntlmssp_flags, user, pass, domain,
920
+ self.challenge_key, client_challenge, ntlm_cli_challenge,
921
+ ntlm_options)
922
+ end
923
+
924
+ # Create the security blob data
925
+ blob = NTLM_UTILS.make_ntlmssp_secblob_auth(domain, name, user, resp_lm, resp_ntlm, enc_session_key, ntlmssp_flags)
926
+
927
+ pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
928
+ self.smb_defaults(pkt['Payload']['SMB'])
929
+
930
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
931
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
932
+ if self.require_signing
933
+ #ascii
934
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
935
+ else
936
+ #ascii
937
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
938
+ end
939
+ pkt['Payload']['SMB'].v['WordCount'] = 12
940
+ pkt['Payload']['SMB'].v['UserID'] = temp_user_id
941
+ pkt['Payload'].v['AndX'] = 255
942
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
943
+ pkt['Payload'].v['MaxMPX'] = 2
944
+ pkt['Payload'].v['VCNum'] = 1
945
+ pkt['Payload'].v['Capabilities'] = 0x8000d05c
946
+ pkt['Payload'].v['SessionKey'] = self.session_id
947
+ pkt['Payload'].v['SecurityBlobLen'] = blob.length
948
+ pkt['Payload'].v['Payload'] = blob + native_data
949
+
950
+ # NOTE: if do_recv is set to false, we cant reach here...
951
+ self.smb_send(pkt.to_s)
952
+
953
+ ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
954
+
955
+ # Make sure that authentication succeeded
956
+ if (ack['Payload']['SMB'].v['ErrorClass'] != 0)
957
+
958
+ if (user.length == 0)
959
+ # Ensure that signing is disabled when we hit this corner case
960
+ self.require_signing = false
961
+
962
+ # Fall back to the non-ntlmssp authentication method
963
+ return self.session_setup_no_ntlmssp(user, pass, domain)
964
+ end
965
+
966
+ failure = XCEPT::ErrorCode.new
967
+ failure.word_count = ack['Payload']['SMB'].v['WordCount']
968
+ failure.command = ack['Payload']['SMB'].v['Command']
969
+ failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
970
+ raise failure
971
+ end
972
+
973
+ self.auth_user_id = ack['Payload']['SMB'].v['UserID']
974
+
975
+ if (ack['Payload'].v['Action'] != 1 and user.length > 0)
976
+ self.auth_user = user
977
+ end
978
+
979
+ return ack
980
+ end
981
+
982
+
983
+ # An exploit helper function for sending arbitrary SPNEGO blobs
984
+ def session_setup_with_ntlmssp_blob(blob = '', do_recv = true, userid = 0)
985
+ native_data = ''
986
+ native_data << self.native_os + "\x00"
987
+ native_data << self.native_lm + "\x00"
988
+
989
+ pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
990
+ self.smb_defaults(pkt['Payload']['SMB'])
991
+
992
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
993
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
994
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
995
+ pkt['Payload']['SMB'].v['WordCount'] = 12
996
+ pkt['Payload']['SMB'].v['UserID'] = userid
997
+ pkt['Payload'].v['AndX'] = 255
998
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
999
+ pkt['Payload'].v['MaxMPX'] = 2
1000
+ pkt['Payload'].v['VCNum'] = 1
1001
+ pkt['Payload'].v['SecurityBlobLen'] = blob.length
1002
+ pkt['Payload'].v['Capabilities'] = 0x8000d05c
1003
+ pkt['Payload'].v['SessionKey'] = self.session_id
1004
+ pkt['Payload'].v['Payload'] = blob + native_data
1005
+
1006
+ ret = self.smb_send(pkt.to_s)
1007
+ return ret if not do_recv
1008
+
1009
+ self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, false)
1010
+ end
1011
+
1012
+
1013
+ # Authenticate using extended security negotiation (NTLMSSP), but stop half-way, using the temporary ID
1014
+ def session_setup_with_ntlmssp_temp(domain = '', name = nil, do_recv = true)
1015
+
1016
+ if (name == nil)
1017
+ name = Rex::Text.rand_text_alphanumeric(16)
1018
+ end
1019
+
1020
+ blob = NTLM_UTILS.make_ntlmssp_secblob_init(domain, name)
1021
+
1022
+ native_data = ''
1023
+ native_data << self.native_os + "\x00"
1024
+ native_data << self.native_lm + "\x00"
1025
+
1026
+ pkt = CONST::SMB_SETUP_NTLMV2_PKT.make_struct
1027
+ self.smb_defaults(pkt['Payload']['SMB'])
1028
+
1029
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_SESSION_SETUP_ANDX
1030
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1031
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1032
+ pkt['Payload']['SMB'].v['WordCount'] = 12
1033
+ pkt['Payload'].v['AndX'] = 255
1034
+ pkt['Payload'].v['MaxBuff'] = 0xffdf
1035
+ pkt['Payload'].v['MaxMPX'] = 2
1036
+ pkt['Payload'].v['VCNum'] = 1
1037
+ pkt['Payload'].v['SecurityBlobLen'] = blob.length
1038
+ pkt['Payload'].v['Capabilities'] = 0x8000d05c
1039
+ pkt['Payload'].v['SessionKey'] = self.session_id
1040
+ pkt['Payload'].v['Payload'] = blob + native_data
1041
+
1042
+ ret = self.smb_send(pkt.to_s)
1043
+ return ret if not do_recv
1044
+
1045
+ ack = self.smb_recv_parse(CONST::SMB_COM_SESSION_SETUP_ANDX, true)
1046
+
1047
+ # The server doesn't know about NTLM_NEGOTIATE, try ntlmv1
1048
+ if (ack['Payload']['SMB'].v['ErrorClass'] == 0x00020002)
1049
+ return session_setup_no_ntlmssp(user, pass, domain)
1050
+ end
1051
+
1052
+ # Make sure the error code tells us to continue processing
1053
+ if (ack['Payload']['SMB'].v['ErrorClass'] != 0xc0000016)
1054
+ failure = XCEPT::ErrorCode.new
1055
+ failure.word_count = ack['Payload']['SMB'].v['WordCount']
1056
+ failure.command = ack['Payload']['SMB'].v['Command']
1057
+ failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
1058
+ raise failure
1059
+ end
1060
+
1061
+ # Extract the SecurityBlob from the response
1062
+ data = ack['Payload'].v['Payload']
1063
+ blob = data.slice!(0, ack['Payload'].v['SecurityBlobLen'])
1064
+
1065
+ # Extract the native lanman and os strings
1066
+ info = data.split(/\x00/n)
1067
+ self.peer_native_os = info[0]
1068
+ self.peer_native_lm = info[1]
1069
+
1070
+ # Save the temporary UserID for use in the next request
1071
+ self.auth_user_id = ack['Payload']['SMB'].v['UserID']
1072
+
1073
+ # Extract the NTLM challenge key the lazy way
1074
+ cidx = blob.index("NTLMSSP\x00\x02\x00\x00\x00")
1075
+
1076
+ if (cidx == -1)
1077
+ raise XCEPT::NTLM2MissingChallenge
1078
+ end
1079
+
1080
+ # Store the challenge key
1081
+ self.challenge_key = blob[cidx + 24, 8]
1082
+
1083
+ return ack
1084
+ end
1085
+
1086
+ # Connect to a specified share with an optional password
1087
+ def tree_connect(share = 'IPC$', pass = '', do_recv = true)
1088
+
1089
+ data = [ pass, share, '?????' ].collect{ |a| a + "\x00" }.join('');
1090
+
1091
+ pkt = CONST::SMB_TREE_CONN_PKT.make_struct
1092
+ self.smb_defaults(pkt['Payload']['SMB'])
1093
+ pkt['Payload']['SMB'].v['TreeID'] = 0
1094
+
1095
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_CONNECT_ANDX
1096
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1097
+ if self.require_signing
1098
+ #ascii
1099
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1100
+ else
1101
+ #ascii
1102
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1103
+ end
1104
+
1105
+ pkt['Payload']['SMB'].v['WordCount'] = 4
1106
+ pkt['Payload'].v['AndX'] = 255
1107
+ pkt['Payload'].v['PasswordLen'] = pass.length + 1
1108
+ pkt['Payload'].v['Capabilities'] = 64
1109
+ pkt['Payload'].v['Payload'] = data
1110
+
1111
+ ret = self.smb_send(pkt.to_s)
1112
+ return ret if not do_recv
1113
+
1114
+ ack = self.smb_recv_parse(CONST::SMB_COM_TREE_CONNECT_ANDX)
1115
+
1116
+ self.last_tree_id = ack['Payload']['SMB'].v['TreeID']
1117
+ # why bother?
1118
+ # info = ack['Payload'].v['Payload'].split(/\x00/)
1119
+
1120
+ return ack
1121
+ end
1122
+
1123
+ # Disconnect from the current tree
1124
+ def tree_disconnect(tree_id = self.last_tree_id, do_recv = true)
1125
+
1126
+ pkt = CONST::SMB_TREE_DISCONN_PKT.make_struct
1127
+ self.smb_defaults(pkt['Payload']['SMB'])
1128
+
1129
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TREE_DISCONNECT
1130
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1131
+ if self.require_signing
1132
+ #ascii
1133
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1134
+ else
1135
+ #ascii
1136
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1137
+ end
1138
+
1139
+ pkt['Payload']['SMB'].v['WordCount'] = 0
1140
+ pkt['Payload']['SMB'].v['TreeID'] = tree_id
1141
+
1142
+ ret = self.smb_send(pkt.to_s)
1143
+ return ret if not do_recv
1144
+
1145
+ ack = self.smb_recv_parse(CONST::SMB_COM_TREE_DISCONNECT)
1146
+
1147
+ if (tree_id == self.last_tree_id)
1148
+ self.last_tree_id = 0
1149
+ end
1150
+
1151
+ return ack
1152
+ end
1153
+
1154
+ # Returns a SMB_CREATE_RES response for a given named pipe
1155
+ def create_pipe(filename, disposition = 1, impersonation = 2)
1156
+ self.create(filename)
1157
+ end
1158
+
1159
+ # Creates a file or opens an existing pipe
1160
+ def create(filename, disposition = 1, impersonation = 2, do_recv = true)
1161
+
1162
+ pkt = CONST::SMB_CREATE_PKT.make_struct
1163
+ self.smb_defaults(pkt['Payload']['SMB'])
1164
+
1165
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_CREATE_ANDX
1166
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1167
+ if self.require_signing
1168
+ #ascii
1169
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1170
+ else
1171
+ #ascii
1172
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1173
+ end
1174
+
1175
+ pkt['Payload']['SMB'].v['WordCount'] = 24
1176
+
1177
+ pkt['Payload'].v['AndX'] = 255
1178
+ pkt['Payload'].v['FileNameLen'] = filename.length
1179
+ pkt['Payload'].v['CreateFlags'] = 0x16
1180
+ pkt['Payload'].v['AccessMask'] = 0x02000000 # Maximum Allowed
1181
+ pkt['Payload'].v['ShareAccess'] = 7
1182
+ pkt['Payload'].v['CreateOptions'] = 0
1183
+ pkt['Payload'].v['Impersonation'] = impersonation
1184
+ pkt['Payload'].v['Disposition'] = disposition
1185
+ pkt['Payload'].v['Payload'] = filename + "\x00"
1186
+
1187
+ ret = self.smb_send(pkt.to_s)
1188
+ return ret if not do_recv
1189
+
1190
+ ack = self.smb_recv_parse(CONST::SMB_COM_NT_CREATE_ANDX)
1191
+
1192
+ # Save off the FileID
1193
+ if (ack['Payload'].v['FileID'] > 0)
1194
+ self.last_file_id = ack['Payload'].v['FileID']
1195
+ end
1196
+
1197
+ return ack
1198
+ end
1199
+
1200
+ # Deletes a file from a share
1201
+ def delete(filename, tree_id = self.last_tree_id, do_recv = true)
1202
+
1203
+ pkt = CONST::SMB_DELETE_PKT.make_struct
1204
+ self.smb_defaults(pkt['Payload']['SMB'])
1205
+
1206
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_DELETE
1207
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1208
+ if self.require_signing
1209
+ #ascii
1210
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1211
+ else
1212
+ #ascii
1213
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1214
+ end
1215
+
1216
+ pkt['Payload']['SMB'].v['TreeID'] = tree_id
1217
+ pkt['Payload']['SMB'].v['WordCount'] = 1
1218
+
1219
+ pkt['Payload'].v['SearchAttributes'] = 0x06
1220
+ pkt['Payload'].v['BufferFormat'] = 4
1221
+ pkt['Payload'].v['Payload'] = filename + "\x00"
1222
+
1223
+ ret = self.smb_send(pkt.to_s)
1224
+ return ret if not do_recv
1225
+
1226
+ ack = self.smb_recv_parse(CONST::SMB_COM_DELETE)
1227
+
1228
+ return ack
1229
+ end
1230
+
1231
+ # Opens an existing file or creates a new one
1232
+ def open(filename, mode = 0x12, access = 0x42, do_recv = true)
1233
+
1234
+ pkt = CONST::SMB_OPEN_PKT.make_struct
1235
+ self.smb_defaults(pkt['Payload']['SMB'])
1236
+
1237
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_OPEN_ANDX
1238
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1239
+ if self.require_signing
1240
+ #ascii
1241
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1242
+ else
1243
+ #ascii
1244
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1245
+ end
1246
+
1247
+ pkt['Payload']['SMB'].v['WordCount'] = 15
1248
+
1249
+ pkt['Payload'].v['AndX'] = 255
1250
+ pkt['Payload'].v['Access'] = access
1251
+ pkt['Payload'].v['SearchAttributes'] = 0x06
1252
+ pkt['Payload'].v['OpenFunction'] = mode
1253
+ pkt['Payload'].v['Payload'] = filename + "\x00"
1254
+
1255
+ ret = self.smb_send(pkt.to_s)
1256
+ return ret if not do_recv
1257
+
1258
+ ack = self.smb_recv_parse(CONST::SMB_COM_OPEN_ANDX)
1259
+
1260
+ # Save off the FileID
1261
+ if (ack['Payload'].v['FileID'] > 0)
1262
+ self.last_file_id = ack['Payload'].v['FileID']
1263
+ end
1264
+
1265
+ return ack
1266
+ end
1267
+
1268
+ # Closes an open file handle
1269
+ def close(file_id = self.last_file_id, tree_id = self.last_tree_id, do_recv = true)
1270
+
1271
+ pkt = CONST::SMB_CLOSE_PKT.make_struct
1272
+ self.smb_defaults(pkt['Payload']['SMB'])
1273
+
1274
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_CLOSE
1275
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1276
+ if self.require_signing
1277
+ #ascii
1278
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1279
+ else
1280
+ #ascii
1281
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1282
+ end
1283
+
1284
+ pkt['Payload']['SMB'].v['TreeID'] = tree_id
1285
+ pkt['Payload']['SMB'].v['WordCount'] = 3
1286
+
1287
+ pkt['Payload'].v['FileID'] = file_id
1288
+ pkt['Payload'].v['LastWrite'] = -1
1289
+
1290
+ ret = self.smb_send(pkt.to_s)
1291
+ return ret if not do_recv
1292
+
1293
+ ack = self.smb_recv_parse(CONST::SMB_COM_CLOSE)
1294
+
1295
+ return ack
1296
+ end
1297
+
1298
+ # Writes data to an open file handle
1299
+ def write(file_id = self.last_file_id, offset = 0, data = '', do_recv = true)
1300
+ pkt = CONST::SMB_WRITE_PKT.make_struct
1301
+ self.smb_defaults(pkt['Payload']['SMB'])
1302
+
1303
+ data_offset = pkt.to_s.length - 4
1304
+
1305
+ filler = EVADE.make_offset_filler(evasion_opts['pad_data'], 4096 - data.length - data_offset)
1306
+
1307
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_WRITE_ANDX
1308
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1309
+ if self.require_signing
1310
+ #ascii
1311
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2805
1312
+ else
1313
+ #ascii
1314
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1315
+ end
1316
+
1317
+ pkt['Payload']['SMB'].v['WordCount'] = 14
1318
+
1319
+ pkt['Payload'].v['AndX'] = 255
1320
+ pkt['Payload'].v['FileID'] = file_id
1321
+ pkt['Payload'].v['Offset'] = offset
1322
+ pkt['Payload'].v['Reserved2'] = -1
1323
+ pkt['Payload'].v['WriteMode'] = 8
1324
+ pkt['Payload'].v['Remaining'] = data.length
1325
+ # pkt['Payload'].v['DataLenHigh'] = (data.length / 65536).to_i
1326
+ pkt['Payload'].v['DataLenLow'] = (data.length % 65536).to_i
1327
+ pkt['Payload'].v['DataOffset'] = data_offset + filler.length
1328
+ pkt['Payload'].v['Payload'] = filler + data
1329
+
1330
+ ret = self.smb_send(pkt.to_s)
1331
+ return ret if not do_recv
1332
+
1333
+ ack = self.smb_recv_parse(CONST::SMB_COM_WRITE_ANDX)
1334
+
1335
+ return ack
1336
+ end
1337
+
1338
+
1339
+ # Reads data from an open file handle
1340
+ def read(file_id = self.last_file_id, offset = 0, data_length = 64000, do_recv = true)
1341
+
1342
+ pkt = CONST::SMB_READ_PKT.make_struct
1343
+ self.smb_defaults(pkt['Payload']['SMB'])
1344
+
1345
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_READ_ANDX
1346
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1347
+ if self.require_signing
1348
+ #ascii
1349
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1350
+ else
1351
+ #ascii
1352
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1353
+ end
1354
+
1355
+ pkt['Payload']['SMB'].v['WordCount'] = 10
1356
+
1357
+ pkt['Payload'].v['AndX'] = 255
1358
+ pkt['Payload'].v['FileID'] = file_id
1359
+ pkt['Payload'].v['Offset'] = offset
1360
+ # pkt['Payload'].v['MaxCountHigh'] = (data_length / 65536).to_i
1361
+ pkt['Payload'].v['MaxCountLow'] = (data_length % 65536).to_i
1362
+ pkt['Payload'].v['MinCount'] = data_length
1363
+ pkt['Payload'].v['Reserved2'] = -1
1364
+
1365
+ ret = self.smb_send(pkt.to_s)
1366
+ return ret if not do_recv
1367
+
1368
+ ack = self.smb_recv_parse(CONST::SMB_COM_READ_ANDX, true)
1369
+
1370
+ err = ack['Payload']['SMB'].v['ErrorClass']
1371
+
1372
+ # Catch some non-fatal error codes
1373
+ if (err != 0 && err != CONST::SMB_ERROR_BUFFER_OVERFLOW)
1374
+ failure = XCEPT::ErrorCode.new
1375
+ failure.word_count = ack['Payload']['SMB'].v['WordCount']
1376
+ failure.command = ack['Payload']['SMB'].v['Command']
1377
+ failure.error_code = ack['Payload']['SMB'].v['ErrorClass']
1378
+ raise failure
1379
+ end
1380
+
1381
+ return ack
1382
+ end
1383
+
1384
+
1385
+ # Perform a transaction against a named pipe
1386
+ def trans_named_pipe(file_id, data = '', no_response = nil)
1387
+ pipe = EVADE.make_trans_named_pipe_name(evasion_opts['pad_file'])
1388
+ self.trans(pipe, '', data, 2, [0x26, file_id].pack('vv'), no_response)
1389
+ end
1390
+
1391
+ # Perform a mailslot write over SMB
1392
+ # Warning: This can kill srv.sys unless MS06-035 is applied
1393
+ def trans_mailslot (name, data = '')
1394
+ # Setup data must be:
1395
+ # Operation: 1 (write)
1396
+ # Priority: 0
1397
+ # Class: Reliable
1398
+ self.trans_maxzero(name, '', data, 3, [1, 0, 1].pack('vvv'), true )
1399
+ end
1400
+
1401
+ # Perform a transaction against a given pipe name
1402
+ def trans(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
1403
+
1404
+ # Null-terminate the pipe parameter if needed
1405
+ if (pipe[-1,1] != "\x00")
1406
+ pipe << "\x00"
1407
+ end
1408
+
1409
+ pkt = CONST::SMB_TRANS_PKT.make_struct
1410
+ self.smb_defaults(pkt['Payload']['SMB'])
1411
+
1412
+ # Packets larger than mlen will cause XP SP2 to disconnect us ;-(
1413
+ mlen = 4200
1414
+
1415
+ # Figure out how much space is taken up by our current arguments
1416
+ xlen = pipe.length + param.length + body.length
1417
+
1418
+ filler1 = ''
1419
+ filler2 = ''
1420
+
1421
+ # Fill any available space depending on the evasion settings
1422
+ if (xlen < mlen)
1423
+ filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
1424
+ filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
1425
+ end
1426
+
1427
+ # Squish the whole thing together
1428
+ data = pipe + filler1 + param + filler2 + body
1429
+
1430
+ # Throw some form of a warning out?
1431
+ if (data.length > mlen)
1432
+ # XXX This call will more than likely fail :-(
1433
+ end
1434
+
1435
+ # Calculate all of the offsets
1436
+ base_offset = pkt.to_s.length + (setup_count * 2) - 4
1437
+ param_offset = base_offset + pipe.length + filler1.length
1438
+ data_offset = param_offset + filler2.length + param.length
1439
+
1440
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
1441
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1442
+ if self.require_signing
1443
+ #ascii
1444
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1445
+ else
1446
+ #ascii
1447
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1448
+ end
1449
+
1450
+ pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
1451
+
1452
+ pkt['Payload'].v['ParamCountTotal'] = param.length
1453
+ pkt['Payload'].v['DataCountTotal'] = body.length
1454
+ pkt['Payload'].v['ParamCountMax'] = 1024
1455
+ pkt['Payload'].v['DataCountMax'] = 65000
1456
+ pkt['Payload'].v['ParamCount'] = param.length
1457
+ pkt['Payload'].v['ParamOffset'] = param_offset
1458
+ pkt['Payload'].v['DataCount'] = body.length
1459
+ pkt['Payload'].v['DataOffset'] = data_offset
1460
+ pkt['Payload'].v['SetupCount'] = setup_count
1461
+ pkt['Payload'].v['SetupData'] = setup_data
1462
+
1463
+ pkt['Payload'].v['Payload'] = data
1464
+
1465
+ if no_response
1466
+ pkt['Payload'].v['Flags'] = 2
1467
+ end
1468
+
1469
+ ret = self.smb_send(pkt.to_s)
1470
+ return ret if no_response or not do_recv
1471
+
1472
+ self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
1473
+ end
1474
+
1475
+
1476
+
1477
+ # Perform a transaction against a given pipe name
1478
+ # Difference from trans: sets MaxParam/MaxData to zero
1479
+ # This is required to trigger mailslot bug :-(
1480
+ def trans_maxzero(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
1481
+
1482
+ # Null-terminate the pipe parameter if needed
1483
+ if (pipe[-1] != 0)
1484
+ pipe << "\x00"
1485
+ end
1486
+
1487
+ pkt = CONST::SMB_TRANS_PKT.make_struct
1488
+ self.smb_defaults(pkt['Payload']['SMB'])
1489
+
1490
+ # Packets larger than mlen will cause XP SP2 to disconnect us ;-(
1491
+ mlen = 4200
1492
+
1493
+ # Figure out how much space is taken up by our current arguments
1494
+ xlen = pipe.length + param.length + body.length
1495
+
1496
+ filler1 = ''
1497
+ filler2 = ''
1498
+
1499
+ # Fill any available space depending on the evasion settings
1500
+ if (xlen < mlen)
1501
+ filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
1502
+ filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
1503
+ end
1504
+
1505
+ # Squish the whole thing together
1506
+ data = pipe + filler1 + param + filler2 + body
1507
+
1508
+ # Throw some form of a warning out?
1509
+ if (data.length > mlen)
1510
+ # XXX This call will more than likely fail :-(
1511
+ end
1512
+
1513
+ # Calculate all of the offsets
1514
+ base_offset = pkt.to_s.length + (setup_count * 2) - 4
1515
+ param_offset = base_offset + pipe.length + filler1.length
1516
+ data_offset = param_offset + filler2.length + param.length
1517
+
1518
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
1519
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1520
+ if self.require_signing
1521
+ #ascii
1522
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1523
+ else
1524
+ #ascii
1525
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1526
+ end
1527
+
1528
+ pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
1529
+
1530
+ pkt['Payload'].v['ParamCountTotal'] = param.length
1531
+ pkt['Payload'].v['DataCountTotal'] = body.length
1532
+ pkt['Payload'].v['ParamCountMax'] = 0
1533
+ pkt['Payload'].v['DataCountMax'] = 0
1534
+ pkt['Payload'].v['ParamCount'] = param.length
1535
+ pkt['Payload'].v['ParamOffset'] = param_offset
1536
+ pkt['Payload'].v['DataCount'] = body.length
1537
+ pkt['Payload'].v['DataOffset'] = data_offset
1538
+ pkt['Payload'].v['SetupCount'] = setup_count
1539
+ pkt['Payload'].v['SetupData'] = setup_data
1540
+
1541
+ pkt['Payload'].v['Payload'] = data
1542
+
1543
+ if no_response
1544
+ pkt['Payload'].v['Flags'] = 2
1545
+ end
1546
+
1547
+ ret = self.smb_send(pkt.to_s)
1548
+ return ret if no_response or not do_recv
1549
+
1550
+ self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
1551
+ end
1552
+
1553
+
1554
+ # Perform a transaction against a given pipe name (no null terminator)
1555
+ def trans_nonull(pipe, param = '', body = '', setup_count = 0, setup_data = '', no_response = false, do_recv = true)
1556
+
1557
+ pkt = CONST::SMB_TRANS_PKT.make_struct
1558
+ self.smb_defaults(pkt['Payload']['SMB'])
1559
+
1560
+ # Packets larger than mlen will cause XP SP2 to disconnect us ;-(
1561
+ mlen = 4200
1562
+
1563
+ # Figure out how much space is taken up by our current arguments
1564
+ xlen = pipe.length + param.length + body.length
1565
+
1566
+ filler1 = ''
1567
+ filler2 = ''
1568
+
1569
+ # Fill any available space depending on the evasion settings
1570
+ if (xlen < mlen)
1571
+ filler1 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
1572
+ filler2 = EVADE.make_offset_filler(evasion_opts['pad_data'], (mlen-xlen)/2)
1573
+ end
1574
+
1575
+ # Squish the whole thing together
1576
+ data = pipe + filler1 + param + filler2 + body
1577
+
1578
+ # Throw some form of a warning out?
1579
+ if (data.length > mlen)
1580
+ # XXX This call will more than likely fail :-(
1581
+ end
1582
+
1583
+ # Calculate all of the offsets
1584
+ base_offset = pkt.to_s.length + (setup_count * 2) - 4
1585
+ param_offset = base_offset + pipe.length + filler1.length
1586
+ data_offset = param_offset + filler2.length + param.length
1587
+
1588
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION
1589
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1590
+ if self.require_signing
1591
+ #ascii
1592
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1593
+ else
1594
+ #ascii
1595
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1596
+ end
1597
+
1598
+ pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
1599
+
1600
+ pkt['Payload'].v['ParamCountTotal'] = param.length
1601
+ pkt['Payload'].v['DataCountTotal'] = body.length
1602
+ pkt['Payload'].v['ParamCountMax'] = 0
1603
+ pkt['Payload'].v['DataCountMax'] = 0
1604
+ pkt['Payload'].v['ParamCount'] = param.length
1605
+ pkt['Payload'].v['ParamOffset'] = param_offset
1606
+ pkt['Payload'].v['DataCount'] = body.length
1607
+ pkt['Payload'].v['DataOffset'] = data_offset
1608
+ pkt['Payload'].v['SetupCount'] = setup_count
1609
+ pkt['Payload'].v['SetupData'] = setup_data
1610
+
1611
+ pkt['Payload'].v['Payload'] = data
1612
+
1613
+ if no_response
1614
+ pkt['Payload'].v['Flags'] = 2
1615
+ end
1616
+
1617
+ ret = self.smb_send(pkt.to_s)
1618
+ return ret if no_response or not do_recv
1619
+
1620
+ self.smb_recv_parse(CONST::SMB_COM_TRANSACTION)
1621
+ end
1622
+
1623
+ # Perform a transaction2 request using the specified subcommand, parameters, and data
1624
+ def trans2(subcommand, param = '', body = '', do_recv = true)
1625
+
1626
+ setup_count = 1
1627
+ setup_data = [subcommand].pack('v')
1628
+
1629
+ data = param + body
1630
+
1631
+ pkt = CONST::SMB_TRANS2_PKT.make_struct
1632
+ self.smb_defaults(pkt['Payload']['SMB'])
1633
+
1634
+ base_offset = pkt.to_s.length + (setup_count * 2) - 4
1635
+ param_offset = base_offset
1636
+ data_offset = param_offset + param.length
1637
+
1638
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_TRANSACTION2
1639
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1640
+ if self.require_signing
1641
+ #ascii
1642
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1643
+ else
1644
+ #ascii
1645
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1646
+ end
1647
+
1648
+ pkt['Payload']['SMB'].v['WordCount'] = 14 + setup_count
1649
+
1650
+ pkt['Payload'].v['ParamCountTotal'] = param.length
1651
+ pkt['Payload'].v['DataCountTotal'] = body.length
1652
+ pkt['Payload'].v['ParamCountMax'] = 1024
1653
+ pkt['Payload'].v['DataCountMax'] = 65000
1654
+ pkt['Payload'].v['ParamCount'] = param.length
1655
+ pkt['Payload'].v['ParamOffset'] = param_offset
1656
+ pkt['Payload'].v['DataCount'] = body.length
1657
+ pkt['Payload'].v['DataOffset'] = data_offset
1658
+ pkt['Payload'].v['SetupCount'] = setup_count
1659
+ pkt['Payload'].v['SetupData'] = setup_data
1660
+
1661
+ pkt['Payload'].v['Payload'] = data
1662
+
1663
+ ret = self.smb_send(pkt.to_s)
1664
+ return ret if not do_recv
1665
+
1666
+ ack = self.smb_recv_parse(CONST::SMB_COM_TRANSACTION2)
1667
+
1668
+ return ack
1669
+ end
1670
+
1671
+
1672
+ # Perform a nttransaction request using the specified subcommand, parameters, and data
1673
+ def nttrans(subcommand, param = '', body = '', setup_count = 0, setup_data = '', do_recv = true)
1674
+
1675
+ data = param + body
1676
+
1677
+ pkt = CONST::SMB_NTTRANS_PKT.make_struct
1678
+ self.smb_defaults(pkt['Payload']['SMB'])
1679
+
1680
+ base_offset = pkt.to_s.length + (setup_count * 2) - 4
1681
+ param_offset = base_offset
1682
+ data_offset = param_offset + param.length
1683
+
1684
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT
1685
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1686
+ if self.require_signing
1687
+ #ascii
1688
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1689
+ else
1690
+ #ascii
1691
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1692
+ end
1693
+
1694
+ pkt['Payload']['SMB'].v['WordCount'] = 19 + setup_count
1695
+
1696
+ pkt['Payload'].v['ParamCountTotal'] = param.length
1697
+ pkt['Payload'].v['DataCountTotal'] = body.length
1698
+ pkt['Payload'].v['ParamCountMax'] = 1024
1699
+ pkt['Payload'].v['DataCountMax'] = 65000
1700
+ pkt['Payload'].v['ParamCount'] = param.length
1701
+ pkt['Payload'].v['ParamOffset'] = param_offset
1702
+ pkt['Payload'].v['DataCount'] = body.length
1703
+ pkt['Payload'].v['DataOffset'] = data_offset
1704
+ pkt['Payload'].v['SetupCount'] = setup_count
1705
+ pkt['Payload'].v['SetupData'] = setup_data
1706
+ pkt['Payload'].v['Subcommand'] = subcommand
1707
+
1708
+ pkt['Payload'].v['Payload'] = data
1709
+
1710
+ ret = self.smb_send(pkt.to_s)
1711
+ return ret if not do_recv
1712
+
1713
+ ack = self.smb_recv_parse(CONST::SMB_COM_NT_TRANSACT)
1714
+ return ack
1715
+ end
1716
+
1717
+ # Perform a nttransaction request using the specified subcommand, parameters, and data
1718
+ def nttrans_secondary(param = '', body = '', do_recv = true)
1719
+
1720
+ data = param + body
1721
+
1722
+ pkt = CONST::SMB_NTTRANS_SECONDARY_PKT.make_struct
1723
+ self.smb_defaults(pkt['Payload']['SMB'])
1724
+
1725
+ base_offset = pkt.to_s.length - 4
1726
+ param_offset = base_offset
1727
+ data_offset = param_offset + param.length
1728
+
1729
+ pkt['Payload']['SMB'].v['Command'] = CONST::SMB_COM_NT_TRANSACT_SECONDARY
1730
+ pkt['Payload']['SMB'].v['Flags1'] = 0x18
1731
+ if self.require_signing
1732
+ #ascii
1733
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2807
1734
+ else
1735
+ #ascii
1736
+ pkt['Payload']['SMB'].v['Flags2'] = 0x2801
1737
+ end
1738
+
1739
+ pkt['Payload']['SMB'].v['WordCount'] = 18
1740
+
1741
+ pkt['Payload'].v['ParamCountTotal'] = param.length
1742
+ pkt['Payload'].v['DataCountTotal'] = body.length
1743
+ pkt['Payload'].v['ParamCount'] = param.length
1744
+ pkt['Payload'].v['ParamOffset'] = param_offset
1745
+ pkt['Payload'].v['DataCount'] = body.length
1746
+ pkt['Payload'].v['DataOffset'] = data_offset
1747
+
1748
+ pkt['Payload'].v['Payload'] = data
1749
+
1750
+ ret = self.smb_send(pkt.to_s)
1751
+ return ret if not do_recv
1752
+
1753
+ ack = self.smb_recv_parse(CONST::SMB_COM_NT_TRANSACT_SECONDARY)
1754
+ return ack
1755
+ end
1756
+
1757
+ def queryfs(level)
1758
+ parm = [level].pack('v')
1759
+
1760
+ begin
1761
+ resp = trans2(CONST::TRANS2_QUERY_FS_INFO, parm, '')
1762
+
1763
+ pcnt = resp['Payload'].v['ParamCount']
1764
+ dcnt = resp['Payload'].v['DataCount']
1765
+ poff = resp['Payload'].v['ParamOffset']
1766
+ doff = resp['Payload'].v['DataOffset']
1767
+
1768
+ # Get the raw packet bytes
1769
+ resp_rpkt = resp.to_s
1770
+
1771
+ # Remove the NetBIOS header
1772
+ resp_rpkt.slice!(0, 4)
1773
+
1774
+ resp_parm = resp_rpkt[poff, pcnt]
1775
+ resp_data = resp_rpkt[doff, dcnt]
1776
+ return resp_data
1777
+
1778
+ rescue ::Exception
1779
+ raise $!
1780
+ end
1781
+ end
1782
+
1783
+ def symlink(src,dst)
1784
+ parm = [513, 0x00000000].pack('vV') + src + "\x00"
1785
+
1786
+ begin
1787
+ resp = trans2(CONST::TRANS2_SET_PATH_INFO, parm, dst + "\x00")
1788
+
1789
+ pcnt = resp['Payload'].v['ParamCount']
1790
+ dcnt = resp['Payload'].v['DataCount']
1791
+ poff = resp['Payload'].v['ParamOffset']
1792
+ doff = resp['Payload'].v['DataOffset']
1793
+
1794
+ # Get the raw packet bytes
1795
+ resp_rpkt = resp.to_s
1796
+
1797
+ # Remove the NetBIOS header
1798
+ resp_rpkt.slice!(0, 4)
1799
+
1800
+ resp_parm = resp_rpkt[poff, pcnt]
1801
+ resp_data = resp_rpkt[doff, dcnt]
1802
+ return resp_data
1803
+
1804
+ rescue ::Exception
1805
+ raise $!
1806
+ end
1807
+ end
1808
+
1809
+ # Obtains allocation information on the mounted tree
1810
+ def queryfs_info_allocation
1811
+ data = queryfs(CONST::SMB_INFO_ALLOCATION)
1812
+ head = %w{fs_id sectors_per_unit unit_total units_available bytes_per_sector}
1813
+ vals = data.unpack('VVVVv')
1814
+ info = { }
1815
+ head.each_index {|i| info[head[i]]=vals[i]}
1816
+ return info
1817
+ end
1818
+
1819
+ # Obtains volume information on the mounted tree
1820
+ def queryfs_info_volume
1821
+ data = queryfs(CONST::SMB_INFO_VOLUME)
1822
+ vals = data.unpack('VCA*')
1823
+ return {
1824
+ 'serial' => vals[0],
1825
+ 'label' => vals[2][0,vals[1]].gsub("\x00", '')
1826
+ }
1827
+ end
1828
+
1829
+ # Obtains file system volume information on the mounted tree
1830
+ def queryfs_fs_volume
1831
+ data = queryfs(CONST::SMB_QUERY_FS_VOLUME_INFO)
1832
+ vals = data.unpack('VVVVCCA*')
1833
+ return {
1834
+ 'create_time' => (vals[1] << 32) + vals[0],
1835
+ 'serial' => vals[2],
1836
+ 'label' => vals[6][0,vals[3]].gsub("\x00", '')
1837
+ }
1838
+ end
1839
+
1840
+ # Obtains file system size information on the mounted tree
1841
+ def queryfs_fs_size
1842
+ data = queryfs(CONST::SMB_QUERY_FS_SIZE_INFO)
1843
+ vals = data.unpack('VVVVVV')
1844
+ return {
1845
+ 'total_alloc_units' => (vals[1] << 32) + vals[0],
1846
+ 'total_free_units' => (vals[3] << 32) + vals[2],
1847
+ 'sectors_per_unit' => vals[4],
1848
+ 'bytes_per_sector' => vals[5]
1849
+ }
1850
+ end
1851
+
1852
+ # Obtains file system device information on the mounted tree
1853
+ def queryfs_fs_device
1854
+ data = queryfs(CONST::SMB_QUERY_FS_DEVICE_INFO)
1855
+ vals = data.unpack('VV')
1856
+ return {
1857
+ 'device_type' => vals[0],
1858
+ 'device_chars' => vals[1],
1859
+ }
1860
+ end
1861
+
1862
+ # Obtains file system attribute information on the mounted tree
1863
+ def queryfs_fs_attribute
1864
+ data = queryfs(CONST::SMB_QUERY_FS_ATTRIBUTE_INFO)
1865
+ vals = data.unpack('VVVA*')
1866
+ return {
1867
+ 'fs_attributes' => vals[0],
1868
+ 'max_file_name' => vals[1],
1869
+ 'fs_name' => vals[3][0, vals[2]].gsub("\x00", '')
1870
+ }
1871
+ end
1872
+
1873
+ # Enumerates a specific path on the mounted tree
1874
+ def find_first(path)
1875
+ files = { }
1876
+ parm = [
1877
+ 26, # Search for ALL files
1878
+ 20, # Maximum search count
1879
+ 6, # Resume and Close on End of Search
1880
+ 260, # Level of interest
1881
+ 0, # Storage type is zero
1882
+ ].pack('vvvvV') + path + "\x00"
1883
+
1884
+ resp = trans2(CONST::TRANS2_FIND_FIRST2, parm, '')
1885
+ search_next = 0
1886
+
1887
+ # Loop until we run out of results
1888
+ loop do
1889
+ pcnt = resp['Payload'].v['ParamCount']
1890
+ dcnt = resp['Payload'].v['DataCount']
1891
+ poff = resp['Payload'].v['ParamOffset']
1892
+ doff = resp['Payload'].v['DataOffset']
1893
+
1894
+ # Get the raw packet bytes
1895
+ resp_rpkt = resp.to_s
1896
+
1897
+ # Remove the NetBIOS header
1898
+ resp_rpkt.slice!(0, 4)
1899
+
1900
+ resp_parm = resp_rpkt[poff, pcnt]
1901
+ resp_data = resp_rpkt[doff, dcnt]
1902
+
1903
+ if search_next == 0
1904
+ # search id, search count, end of search, error offset, last name offset
1905
+ sid, scnt, eos, eoff, loff = resp_parm.unpack('v5')
1906
+ else
1907
+ # FIND_NEXT doesn't return a SID
1908
+ scnt, eos, eoff, loff = resp_parm.unpack('v4')
1909
+ end
1910
+
1911
+ didx = 0
1912
+ while (didx < resp_data.length)
1913
+ info_buff = resp_data[didx, 70]
1914
+ break if info_buff.length != 70
1915
+
1916
+ info = info_buff.unpack(
1917
+ 'V'+ # Next Entry Offset
1918
+ 'V'+ # File Index
1919
+ 'VV'+ # Time Create
1920
+ 'VV'+ # Time Last Access
1921
+ 'VV'+ # Time Last Write
1922
+ 'VV'+ # Time Change
1923
+ 'VV'+ # End of File
1924
+ 'VV'+ # Allocation Size
1925
+ 'V'+ # File Attributes
1926
+ 'V'+ # File Name Length
1927
+ 'V'+ # Extended Attr List Length
1928
+ 'C'+ # Short File Name Length
1929
+ 'C' # Reserved
1930
+ )
1931
+
1932
+ name = resp_data[didx + 70 + 24, info[15]]
1933
+
1934
+ # Verify that the filename was actually present
1935
+ break unless name
1936
+
1937
+ # Key the file list minus any trailing nulls
1938
+ files[name.sub(/\x00+$/n, '')] =
1939
+ {
1940
+ 'type' => ( info[14] & CONST::SMB_EXT_FILE_ATTR_DIRECTORY == 0 ) ? 'F' : 'D',
1941
+ 'attr' => info[14],
1942
+ 'info' => info
1943
+ }
1944
+
1945
+ break if info[0] == 0
1946
+ didx += info[0]
1947
+ end
1948
+
1949
+ last_search_id = sid
1950
+ last_offset = loff
1951
+ last_filename = name
1952
+
1953
+ # Exit the search if we reached the end of our results
1954
+ break if (eos != 0 or last_search_id.nil? or last_offset.to_i == 0)
1955
+
1956
+ # If we aren't at the end of the search, run find_next
1957
+ resp = find_next(last_search_id, last_offset, last_filename)
1958
+
1959
+ # Flip bit so response params will parse correctly
1960
+ search_next = 1
1961
+ end
1962
+
1963
+ files
1964
+ end
1965
+
1966
+ # Supplements find_first if file/dir count exceeds max search count
1967
+ def find_next(sid, resume_key, last_filename)
1968
+
1969
+ parm = [
1970
+ sid, # Search ID
1971
+ 20, # Maximum search count (Size of 20 keeps response to 1 packet)
1972
+ 260, # Level of interest
1973
+ resume_key, # Resume key from previous (Last name offset)
1974
+ 6, # Close search if end of search
1975
+ ].pack('vvvVv') +
1976
+ last_filename.to_s + # Last filename returned from find_first or find_next
1977
+ "\x00" # Terminate the file name
1978
+
1979
+ # Returns the FIND_NEXT2 response packet for parsing by the find_first function
1980
+ trans2(CONST::TRANS2_FIND_NEXT2, parm, '')
1981
+ end
1982
+
1983
+ # Recursively search for files matching a regular expression
1984
+ def file_search(current_path, regex, depth)
1985
+ depth -= 1
1986
+ return [] if depth < 0
1987
+
1988
+ results = find_first(current_path + "*")
1989
+ files = []
1990
+
1991
+ results.each_pair do |fname, finfo|
1992
+
1993
+ # Skip current and parent directory results
1994
+ next if %W{. ..}.include?(fname)
1995
+
1996
+ # Verify the results contain an attribute
1997
+ next unless finfo and finfo['attr']
1998
+
1999
+ if finfo['attr'] & CONST::SMB_EXT_FILE_ATTR_DIRECTORY == 0
2000
+ # Add any matching files to our result set
2001
+ files << "#{current_path}#{fname}" if fname =~ regex
2002
+ else
2003
+ # Recurse into the discovery subdirectory for more files
2004
+ begin
2005
+ search_path = "#{current_path}#{fname}\\"
2006
+ file_search(search_path, regex, depth).each {|fn| files << fn }
2007
+ rescue Rex::Proto::SMB::Exceptions::ErrorCode => e
2008
+
2009
+ # Ignore common errors related to permissions and non-files
2010
+ if %W{
2011
+ STATUS_ACCESS_DENIED
2012
+ STATUS_NO_SUCH_FILE
2013
+ STATUS_OBJECT_NAME_NOT_FOUND
2014
+ STATUS_OBJECT_PATH_NOT_FOUND
2015
+ }.include? e.get_error(e.error_code)
2016
+ next
2017
+ end
2018
+
2019
+ $stderr.puts [e, e.get_error(e.error_code), search_path]
2020
+
2021
+ raise e
2022
+ end
2023
+ end
2024
+
2025
+ end
2026
+
2027
+ files.uniq
2028
+ end
2029
+
2030
+ # Creates a new directory on the mounted tree
2031
+ def create_directory(name)
2032
+ files = { }
2033
+ parm = [0].pack('V') + name + "\x00"
2034
+ resp = trans2(CONST::TRANS2_CREATE_DIRECTORY, parm, '')
2035
+ end
2036
+
2037
+ # public read/write methods
2038
+ attr_accessor :native_os, :native_lm, :encrypt_passwords, :extended_security, :read_timeout, :evasion_opts
2039
+ attr_accessor :verify_signature, :use_ntlmv2, :usentlm2_session, :send_lm, :use_lanman_key, :send_ntlm
2040
+ attr_accessor :system_time, :system_zone
2041
+ attr_accessor :spnopt
2042
+
2043
+ # public read methods
2044
+ attr_reader :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os
2045
+ attr_reader :default_domain, :default_name, :auth_user, :auth_user_id
2046
+ attr_reader :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id
2047
+ attr_reader :dns_host_name, :dns_domain_name
2048
+ attr_reader :security_mode, :server_guid
2049
+ attr_reader :sequence_counter,:signing_key, :require_signing
2050
+
2051
+ # private write methods
2052
+ attr_writer :dialect, :session_id, :challenge_key, :peer_native_lm, :peer_native_os
2053
+ attr_writer :default_domain, :default_name, :auth_user, :auth_user_id
2054
+ attr_writer :dns_host_name, :dns_domain_name
2055
+ attr_writer :multiplex_id, :last_tree_id, :last_file_id, :process_id, :last_search_id
2056
+ attr_writer :security_mode, :server_guid
2057
+ attr_writer :sequence_counter,:signing_key, :require_signing
2058
+
2059
+ attr_accessor :socket
2060
+
2061
+ end
2062
+ end
2063
+ end
2064
+ end