librex 0.0.68 → 0.0.70

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