librex 0.0.20 → 0.0.21

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