librex 0.0.68 → 0.0.70

Sign up to get free protection for your applications and to get access to all the features.
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