librex 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (434) hide show
  1. data/lib/rex/LICENSE +29 -0
  2. data/lib/rex/arch.rb +103 -0
  3. data/lib/rex/arch/sparc.rb +75 -0
  4. data/lib/rex/arch/sparc.rb.ut.rb +18 -0
  5. data/lib/rex/arch/x86.rb +513 -0
  6. data/lib/rex/arch/x86.rb.ut.rb +93 -0
  7. data/lib/rex/assembly/nasm.rb +104 -0
  8. data/lib/rex/assembly/nasm.rb.ut.rb +22 -0
  9. data/lib/rex/codepage.map +104 -0
  10. data/lib/rex/compat.rb +311 -0
  11. data/lib/rex/constants.rb +113 -0
  12. data/lib/rex/elfparsey.rb +11 -0
  13. data/lib/rex/elfparsey/elf.rb +123 -0
  14. data/lib/rex/elfparsey/elfbase.rb +258 -0
  15. data/lib/rex/elfparsey/exceptions.rb +27 -0
  16. data/lib/rex/elfscan.rb +12 -0
  17. data/lib/rex/elfscan/scanner.rb +207 -0
  18. data/lib/rex/elfscan/search.rb +46 -0
  19. data/lib/rex/encoder/alpha2.rb +31 -0
  20. data/lib/rex/encoder/alpha2/alpha_mixed.rb +68 -0
  21. data/lib/rex/encoder/alpha2/alpha_upper.rb +79 -0
  22. data/lib/rex/encoder/alpha2/generic.rb +114 -0
  23. data/lib/rex/encoder/alpha2/unicode_mixed.rb +117 -0
  24. data/lib/rex/encoder/alpha2/unicode_upper.rb +129 -0
  25. data/lib/rex/encoder/ndr.rb +89 -0
  26. data/lib/rex/encoder/ndr.rb.ut.rb +44 -0
  27. data/lib/rex/encoder/nonalpha.rb +61 -0
  28. data/lib/rex/encoder/nonupper.rb +64 -0
  29. data/lib/rex/encoder/xdr.rb +106 -0
  30. data/lib/rex/encoder/xdr.rb.ut.rb +29 -0
  31. data/lib/rex/encoder/xor.rb +69 -0
  32. data/lib/rex/encoder/xor/dword.rb +13 -0
  33. data/lib/rex/encoder/xor/dword_additive.rb +13 -0
  34. data/lib/rex/encoders/xor_dword.rb +35 -0
  35. data/lib/rex/encoders/xor_dword_additive.rb +53 -0
  36. data/lib/rex/encoders/xor_dword_additive.rb.ut.rb +12 -0
  37. data/lib/rex/encoding/xor.rb +20 -0
  38. data/lib/rex/encoding/xor.rb.ts.rb +14 -0
  39. data/lib/rex/encoding/xor/byte.rb +15 -0
  40. data/lib/rex/encoding/xor/byte.rb.ut.rb +21 -0
  41. data/lib/rex/encoding/xor/dword.rb +21 -0
  42. data/lib/rex/encoding/xor/dword.rb.ut.rb +15 -0
  43. data/lib/rex/encoding/xor/dword_additive.rb +92 -0
  44. data/lib/rex/encoding/xor/dword_additive.rb.ut.rb +15 -0
  45. data/lib/rex/encoding/xor/exceptions.rb +17 -0
  46. data/lib/rex/encoding/xor/generic.rb +146 -0
  47. data/lib/rex/encoding/xor/generic.rb.ut.rb +120 -0
  48. data/lib/rex/encoding/xor/qword.rb +15 -0
  49. data/lib/rex/encoding/xor/word.rb +21 -0
  50. data/lib/rex/encoding/xor/word.rb.ut.rb +13 -0
  51. data/lib/rex/exceptions.rb +275 -0
  52. data/lib/rex/exceptions.rb.ut.rb +44 -0
  53. data/lib/rex/exploitation/cmdstager.rb +9 -0
  54. data/lib/rex/exploitation/cmdstager/base.rb +175 -0
  55. data/lib/rex/exploitation/cmdstager/debug_asm.rb +142 -0
  56. data/lib/rex/exploitation/cmdstager/debug_write.rb +136 -0
  57. data/lib/rex/exploitation/cmdstager/tftp.rb +63 -0
  58. data/lib/rex/exploitation/cmdstager/vbs.rb +128 -0
  59. data/lib/rex/exploitation/egghunter.rb +277 -0
  60. data/lib/rex/exploitation/egghunter.rb.ut.rb +25 -0
  61. data/lib/rex/exploitation/encryptjs.rb +77 -0
  62. data/lib/rex/exploitation/heaplib.js.b64 +331 -0
  63. data/lib/rex/exploitation/heaplib.rb +94 -0
  64. data/lib/rex/exploitation/javascriptosdetect.rb +897 -0
  65. data/lib/rex/exploitation/obfuscatejs.rb +335 -0
  66. data/lib/rex/exploitation/omelet.rb +320 -0
  67. data/lib/rex/exploitation/omelet.rb.ut.rb +13 -0
  68. data/lib/rex/exploitation/opcodedb.rb +818 -0
  69. data/lib/rex/exploitation/opcodedb.rb.ut.rb +279 -0
  70. data/lib/rex/exploitation/seh.rb +92 -0
  71. data/lib/rex/exploitation/seh.rb.ut.rb +19 -0
  72. data/lib/rex/file.rb +112 -0
  73. data/lib/rex/file.rb.ut.rb +16 -0
  74. data/lib/rex/image_source.rb +12 -0
  75. data/lib/rex/image_source/disk.rb +60 -0
  76. data/lib/rex/image_source/image_source.rb +46 -0
  77. data/lib/rex/image_source/memory.rb +37 -0
  78. data/lib/rex/io/bidirectional_pipe.rb +157 -0
  79. data/lib/rex/io/datagram_abstraction.rb +35 -0
  80. data/lib/rex/io/ring_buffer.rb +364 -0
  81. data/lib/rex/io/stream.rb +319 -0
  82. data/lib/rex/io/stream_abstraction.rb +197 -0
  83. data/lib/rex/io/stream_server.rb +211 -0
  84. data/lib/rex/job_container.rb +187 -0
  85. data/lib/rex/logging.rb +4 -0
  86. data/lib/rex/logging/log_dispatcher.rb +179 -0
  87. data/lib/rex/logging/log_sink.rb +42 -0
  88. data/lib/rex/logging/sinks/flatfile.rb +55 -0
  89. data/lib/rex/logging/sinks/stderr.rb +43 -0
  90. data/lib/rex/machparsey.rb +9 -0
  91. data/lib/rex/machparsey/exceptions.rb +34 -0
  92. data/lib/rex/machparsey/mach.rb +209 -0
  93. data/lib/rex/machparsey/machbase.rb +408 -0
  94. data/lib/rex/machscan.rb +9 -0
  95. data/lib/rex/machscan/scanner.rb +217 -0
  96. data/lib/rex/mime.rb +9 -0
  97. data/lib/rex/mime/header.rb +77 -0
  98. data/lib/rex/mime/message.rb +144 -0
  99. data/lib/rex/mime/part.rb +20 -0
  100. data/lib/rex/nop/opty2.rb +108 -0
  101. data/lib/rex/nop/opty2.rb.ut.rb +23 -0
  102. data/lib/rex/nop/opty2_tables.rb +300 -0
  103. data/lib/rex/ole.rb +205 -0
  104. data/lib/rex/ole/clsid.rb +47 -0
  105. data/lib/rex/ole/difat.rb +141 -0
  106. data/lib/rex/ole/directory.rb +231 -0
  107. data/lib/rex/ole/direntry.rb +240 -0
  108. data/lib/rex/ole/docs/dependencies.txt +8 -0
  109. data/lib/rex/ole/docs/references.txt +1 -0
  110. data/lib/rex/ole/fat.rb +99 -0
  111. data/lib/rex/ole/header.rb +204 -0
  112. data/lib/rex/ole/minifat.rb +77 -0
  113. data/lib/rex/ole/propset.rb +144 -0
  114. data/lib/rex/ole/samples/create_ole.rb +27 -0
  115. data/lib/rex/ole/samples/dir.rb +35 -0
  116. data/lib/rex/ole/samples/dump_stream.rb +34 -0
  117. data/lib/rex/ole/samples/ole_info.rb +23 -0
  118. data/lib/rex/ole/storage.rb +395 -0
  119. data/lib/rex/ole/stream.rb +53 -0
  120. data/lib/rex/ole/substorage.rb +49 -0
  121. data/lib/rex/ole/util.rb +157 -0
  122. data/lib/rex/parser/arguments.rb +97 -0
  123. data/lib/rex/parser/arguments.rb.ut.rb +67 -0
  124. data/lib/rex/parser/ini.rb +185 -0
  125. data/lib/rex/parser/ini.rb.ut.rb +29 -0
  126. data/lib/rex/parser/ip360_aspl_xml.rb +102 -0
  127. data/lib/rex/parser/ip360_xml.rb +97 -0
  128. data/lib/rex/parser/nessus_xml.rb +118 -0
  129. data/lib/rex/parser/netsparker_xml.rb +94 -0
  130. data/lib/rex/parser/nexpose_xml.rb +136 -0
  131. data/lib/rex/parser/nmap_xml.rb +137 -0
  132. data/lib/rex/parser/retina_xml.rb +109 -0
  133. data/lib/rex/payloads.rb +1 -0
  134. data/lib/rex/payloads/win32.rb +2 -0
  135. data/lib/rex/payloads/win32/common.rb +26 -0
  136. data/lib/rex/payloads/win32/kernel.rb +53 -0
  137. data/lib/rex/payloads/win32/kernel/common.rb +54 -0
  138. data/lib/rex/payloads/win32/kernel/migration.rb +12 -0
  139. data/lib/rex/payloads/win32/kernel/recovery.rb +50 -0
  140. data/lib/rex/payloads/win32/kernel/stager.rb +194 -0
  141. data/lib/rex/peparsey.rb +12 -0
  142. data/lib/rex/peparsey/exceptions.rb +32 -0
  143. data/lib/rex/peparsey/pe.rb +212 -0
  144. data/lib/rex/peparsey/pe_memdump.rb +63 -0
  145. data/lib/rex/peparsey/pebase.rb +1680 -0
  146. data/lib/rex/peparsey/section.rb +136 -0
  147. data/lib/rex/pescan.rb +13 -0
  148. data/lib/rex/pescan/analyze.rb +309 -0
  149. data/lib/rex/pescan/scanner.rb +206 -0
  150. data/lib/rex/pescan/search.rb +56 -0
  151. data/lib/rex/platforms.rb +1 -0
  152. data/lib/rex/platforms/windows.rb +51 -0
  153. data/lib/rex/poly.rb +132 -0
  154. data/lib/rex/poly/block.rb +477 -0
  155. data/lib/rex/poly/register.rb +100 -0
  156. data/lib/rex/poly/register/x86.rb +40 -0
  157. data/lib/rex/post.rb +8 -0
  158. data/lib/rex/post/dir.rb +51 -0
  159. data/lib/rex/post/file.rb +172 -0
  160. data/lib/rex/post/file_stat.rb +220 -0
  161. data/lib/rex/post/gen.pl +13 -0
  162. data/lib/rex/post/io.rb +182 -0
  163. data/lib/rex/post/meterpreter.rb +4 -0
  164. data/lib/rex/post/meterpreter/channel.rb +445 -0
  165. data/lib/rex/post/meterpreter/channel_container.rb +54 -0
  166. data/lib/rex/post/meterpreter/channels/pool.rb +160 -0
  167. data/lib/rex/post/meterpreter/channels/pools/file.rb +62 -0
  168. data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +103 -0
  169. data/lib/rex/post/meterpreter/channels/stream.rb +87 -0
  170. data/lib/rex/post/meterpreter/client.rb +364 -0
  171. data/lib/rex/post/meterpreter/client_core.rb +274 -0
  172. data/lib/rex/post/meterpreter/dependencies.rb +3 -0
  173. data/lib/rex/post/meterpreter/extension.rb +32 -0
  174. data/lib/rex/post/meterpreter/extensions/espia/espia.rb +58 -0
  175. data/lib/rex/post/meterpreter/extensions/espia/tlv.rb +16 -0
  176. data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +94 -0
  177. data/lib/rex/post/meterpreter/extensions/incognito/tlv.rb +21 -0
  178. data/lib/rex/post/meterpreter/extensions/networkpug/networkpug.rb +57 -0
  179. data/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb +15 -0
  180. data/lib/rex/post/meterpreter/extensions/priv/fs.rb +118 -0
  181. data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +61 -0
  182. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +111 -0
  183. data/lib/rex/post/meterpreter/extensions/priv/tlv.rb +28 -0
  184. data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +101 -0
  185. data/lib/rex/post/meterpreter/extensions/sniffer/tlv.rb +26 -0
  186. data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +333 -0
  187. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +282 -0
  188. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +266 -0
  189. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +103 -0
  190. data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +48 -0
  191. data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +144 -0
  192. data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +73 -0
  193. data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +56 -0
  194. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +137 -0
  195. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +180 -0
  196. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +167 -0
  197. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +208 -0
  198. data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +6 -0
  199. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +38106 -0
  200. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +31 -0
  201. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +47 -0
  202. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb.ut.rb +36 -0
  203. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +1818 -0
  204. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_iphlpapi.rb +96 -0
  205. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3848 -0
  206. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +26 -0
  207. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ntdll.rb +153 -0
  208. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_shell32.rb +21 -0
  209. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb +3169 -0
  210. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb +599 -0
  211. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +318 -0
  212. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +100 -0
  213. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb +42 -0
  214. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +148 -0
  215. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +127 -0
  216. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +309 -0
  217. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +204 -0
  218. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb +51 -0
  219. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +630 -0
  220. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +75 -0
  221. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb.ut.rb +103 -0
  222. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +149 -0
  223. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +97 -0
  224. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +192 -0
  225. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +41 -0
  226. data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +61 -0
  227. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +370 -0
  228. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +129 -0
  229. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +55 -0
  230. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +336 -0
  231. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +141 -0
  232. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +279 -0
  233. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +193 -0
  234. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +102 -0
  235. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +180 -0
  236. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +211 -0
  237. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +227 -0
  238. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +63 -0
  239. data/lib/rex/post/meterpreter/inbound_packet_handler.rb +30 -0
  240. data/lib/rex/post/meterpreter/object_aliases.rb +83 -0
  241. data/lib/rex/post/meterpreter/packet.rb +688 -0
  242. data/lib/rex/post/meterpreter/packet_dispatcher.rb +431 -0
  243. data/lib/rex/post/meterpreter/packet_parser.rb +94 -0
  244. data/lib/rex/post/meterpreter/packet_response_waiter.rb +83 -0
  245. data/lib/rex/post/meterpreter/ui/console.rb +137 -0
  246. data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +62 -0
  247. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +730 -0
  248. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +108 -0
  249. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +241 -0
  250. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +231 -0
  251. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +61 -0
  252. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +98 -0
  253. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +51 -0
  254. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +132 -0
  255. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +187 -0
  256. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +65 -0
  257. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +442 -0
  258. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +298 -0
  259. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +486 -0
  260. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +315 -0
  261. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +157 -0
  262. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +95 -0
  263. data/lib/rex/post/permission.rb +26 -0
  264. data/lib/rex/post/process.rb +57 -0
  265. data/lib/rex/post/thread.rb +57 -0
  266. data/lib/rex/post/ui.rb +52 -0
  267. data/lib/rex/proto.rb +13 -0
  268. data/lib/rex/proto.rb.ts.rb +8 -0
  269. data/lib/rex/proto/dcerpc.rb +6 -0
  270. data/lib/rex/proto/dcerpc.rb.ts.rb +9 -0
  271. data/lib/rex/proto/dcerpc/client.rb +361 -0
  272. data/lib/rex/proto/dcerpc/client.rb.ut.rb +491 -0
  273. data/lib/rex/proto/dcerpc/exceptions.rb +150 -0
  274. data/lib/rex/proto/dcerpc/handle.rb +47 -0
  275. data/lib/rex/proto/dcerpc/handle.rb.ut.rb +85 -0
  276. data/lib/rex/proto/dcerpc/ndr.rb +72 -0
  277. data/lib/rex/proto/dcerpc/ndr.rb.ut.rb +41 -0
  278. data/lib/rex/proto/dcerpc/packet.rb +253 -0
  279. data/lib/rex/proto/dcerpc/packet.rb.ut.rb +56 -0
  280. data/lib/rex/proto/dcerpc/response.rb +187 -0
  281. data/lib/rex/proto/dcerpc/response.rb.ut.rb +15 -0
  282. data/lib/rex/proto/dcerpc/uuid.rb +84 -0
  283. data/lib/rex/proto/dcerpc/uuid.rb.ut.rb +46 -0
  284. data/lib/rex/proto/dhcp.rb +7 -0
  285. data/lib/rex/proto/dhcp/constants.rb +33 -0
  286. data/lib/rex/proto/dhcp/server.rb +292 -0
  287. data/lib/rex/proto/drda.rb +5 -0
  288. data/lib/rex/proto/drda.rb.ts.rb +17 -0
  289. data/lib/rex/proto/drda/constants.rb +49 -0
  290. data/lib/rex/proto/drda/constants.rb.ut.rb +23 -0
  291. data/lib/rex/proto/drda/packet.rb +252 -0
  292. data/lib/rex/proto/drda/packet.rb.ut.rb +109 -0
  293. data/lib/rex/proto/drda/utils.rb +123 -0
  294. data/lib/rex/proto/drda/utils.rb.ut.rb +84 -0
  295. data/lib/rex/proto/http.rb +5 -0
  296. data/lib/rex/proto/http.rb.ts.rb +12 -0
  297. data/lib/rex/proto/http/client.rb +821 -0
  298. data/lib/rex/proto/http/client.rb.ut.rb +95 -0
  299. data/lib/rex/proto/http/handler.rb +46 -0
  300. data/lib/rex/proto/http/handler/erb.rb +128 -0
  301. data/lib/rex/proto/http/handler/erb.rb.ut.rb +21 -0
  302. data/lib/rex/proto/http/handler/erb.rb.ut.rb.rhtml +1 -0
  303. data/lib/rex/proto/http/handler/proc.rb +60 -0
  304. data/lib/rex/proto/http/handler/proc.rb.ut.rb +24 -0
  305. data/lib/rex/proto/http/header.rb +161 -0
  306. data/lib/rex/proto/http/header.rb.ut.rb +46 -0
  307. data/lib/rex/proto/http/packet.rb +407 -0
  308. data/lib/rex/proto/http/packet.rb.ut.rb +165 -0
  309. data/lib/rex/proto/http/request.rb +356 -0
  310. data/lib/rex/proto/http/request.rb.ut.rb +214 -0
  311. data/lib/rex/proto/http/response.rb +90 -0
  312. data/lib/rex/proto/http/response.rb.ut.rb +149 -0
  313. data/lib/rex/proto/http/server.rb +369 -0
  314. data/lib/rex/proto/http/server.rb.ut.rb +79 -0
  315. data/lib/rex/proto/ntlm.rb +7 -0
  316. data/lib/rex/proto/ntlm.rb.ut.rb +177 -0
  317. data/lib/rex/proto/ntlm/base.rb +326 -0
  318. data/lib/rex/proto/ntlm/constants.rb +74 -0
  319. data/lib/rex/proto/ntlm/crypt.rb +415 -0
  320. data/lib/rex/proto/ntlm/exceptions.rb +16 -0
  321. data/lib/rex/proto/ntlm/message.rb +536 -0
  322. data/lib/rex/proto/ntlm/utils.rb +764 -0
  323. data/lib/rex/proto/proxy/socks4a.rb +440 -0
  324. data/lib/rex/proto/rfb.rb +19 -0
  325. data/lib/rex/proto/rfb.rb.ut.rb +37 -0
  326. data/lib/rex/proto/rfb/cipher.rb +84 -0
  327. data/lib/rex/proto/rfb/client.rb +207 -0
  328. data/lib/rex/proto/rfb/constants.rb +52 -0
  329. data/lib/rex/proto/smb.rb +7 -0
  330. data/lib/rex/proto/smb.rb.ts.rb +8 -0
  331. data/lib/rex/proto/smb/client.rb +1952 -0
  332. data/lib/rex/proto/smb/client.rb.ut.rb +223 -0
  333. data/lib/rex/proto/smb/constants.rb +1047 -0
  334. data/lib/rex/proto/smb/constants.rb.ut.rb +18 -0
  335. data/lib/rex/proto/smb/crypt.rb +36 -0
  336. data/lib/rex/proto/smb/evasions.rb +66 -0
  337. data/lib/rex/proto/smb/exceptions.rb +858 -0
  338. data/lib/rex/proto/smb/simpleclient.rb +306 -0
  339. data/lib/rex/proto/smb/simpleclient.rb.ut.rb +128 -0
  340. data/lib/rex/proto/smb/utils.rb +103 -0
  341. data/lib/rex/proto/smb/utils.rb.ut.rb +20 -0
  342. data/lib/rex/proto/sunrpc.rb +1 -0
  343. data/lib/rex/proto/sunrpc/client.rb +195 -0
  344. data/lib/rex/proto/tftp.rb +12 -0
  345. data/lib/rex/proto/tftp/constants.rb +39 -0
  346. data/lib/rex/proto/tftp/server.rb +497 -0
  347. data/lib/rex/proto/tftp/server.rb.ut.rb +28 -0
  348. data/lib/rex/script.rb +42 -0
  349. data/lib/rex/script/base.rb +59 -0
  350. data/lib/rex/script/meterpreter.rb +15 -0
  351. data/lib/rex/script/shell.rb +9 -0
  352. data/lib/rex/service.rb +48 -0
  353. data/lib/rex/service_manager.rb +141 -0
  354. data/lib/rex/service_manager.rb.ut.rb +32 -0
  355. data/lib/rex/services/local_relay.rb +423 -0
  356. data/lib/rex/socket.rb +684 -0
  357. data/lib/rex/socket.rb.ut.rb +107 -0
  358. data/lib/rex/socket/comm.rb +119 -0
  359. data/lib/rex/socket/comm/local.rb +412 -0
  360. data/lib/rex/socket/comm/local.rb.ut.rb +75 -0
  361. data/lib/rex/socket/ip.rb +130 -0
  362. data/lib/rex/socket/parameters.rb +345 -0
  363. data/lib/rex/socket/parameters.rb.ut.rb +51 -0
  364. data/lib/rex/socket/range_walker.rb +346 -0
  365. data/lib/rex/socket/range_walker.rb.ut.rb +55 -0
  366. data/lib/rex/socket/ssl_tcp.rb +184 -0
  367. data/lib/rex/socket/ssl_tcp.rb.ut.rb +39 -0
  368. data/lib/rex/socket/ssl_tcp_server.rb +122 -0
  369. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +61 -0
  370. data/lib/rex/socket/subnet_walker.rb +75 -0
  371. data/lib/rex/socket/subnet_walker.rb.ut.rb +28 -0
  372. data/lib/rex/socket/switch_board.rb +278 -0
  373. data/lib/rex/socket/switch_board.rb.ut.rb +52 -0
  374. data/lib/rex/socket/tcp.rb +76 -0
  375. data/lib/rex/socket/tcp.rb.ut.rb +64 -0
  376. data/lib/rex/socket/tcp_server.rb +66 -0
  377. data/lib/rex/socket/tcp_server.rb.ut.rb +44 -0
  378. data/lib/rex/socket/udp.rb +164 -0
  379. data/lib/rex/socket/udp.rb.ut.rb +44 -0
  380. data/lib/rex/struct2.rb +5 -0
  381. data/lib/rex/struct2/c_struct.rb +181 -0
  382. data/lib/rex/struct2/c_struct_template.rb +39 -0
  383. data/lib/rex/struct2/constant.rb +26 -0
  384. data/lib/rex/struct2/element.rb +44 -0
  385. data/lib/rex/struct2/generic.rb +73 -0
  386. data/lib/rex/struct2/restraint.rb +54 -0
  387. data/lib/rex/struct2/s_string.rb +72 -0
  388. data/lib/rex/struct2/s_struct.rb +111 -0
  389. data/lib/rex/sync.rb +6 -0
  390. data/lib/rex/sync/event.rb +94 -0
  391. data/lib/rex/sync/read_write_lock.rb +176 -0
  392. data/lib/rex/sync/ref.rb +57 -0
  393. data/lib/rex/sync/thread_safe.rb +82 -0
  394. data/lib/rex/test.rb +35 -0
  395. data/lib/rex/text.rb +1163 -0
  396. data/lib/rex/text.rb.ut.rb +190 -0
  397. data/lib/rex/thread_factory.rb +42 -0
  398. data/lib/rex/time.rb +65 -0
  399. data/lib/rex/transformer.rb +115 -0
  400. data/lib/rex/transformer.rb.ut.rb +38 -0
  401. data/lib/rex/ui.rb +21 -0
  402. data/lib/rex/ui/interactive.rb +298 -0
  403. data/lib/rex/ui/output.rb +78 -0
  404. data/lib/rex/ui/output/none.rb +18 -0
  405. data/lib/rex/ui/progress_tracker.rb +96 -0
  406. data/lib/rex/ui/subscriber.rb +149 -0
  407. data/lib/rex/ui/text/color.rb +97 -0
  408. data/lib/rex/ui/text/color.rb.ut.rb +18 -0
  409. data/lib/rex/ui/text/dispatcher_shell.rb +467 -0
  410. data/lib/rex/ui/text/input.rb +117 -0
  411. data/lib/rex/ui/text/input/buffer.rb +75 -0
  412. data/lib/rex/ui/text/input/readline.rb +129 -0
  413. data/lib/rex/ui/text/input/socket.rb +95 -0
  414. data/lib/rex/ui/text/input/stdio.rb +45 -0
  415. data/lib/rex/ui/text/irb_shell.rb +57 -0
  416. data/lib/rex/ui/text/output.rb +80 -0
  417. data/lib/rex/ui/text/output/buffer.rb +61 -0
  418. data/lib/rex/ui/text/output/file.rb +43 -0
  419. data/lib/rex/ui/text/output/socket.rb +43 -0
  420. data/lib/rex/ui/text/output/stdio.rb +40 -0
  421. data/lib/rex/ui/text/progress_tracker.rb +56 -0
  422. data/lib/rex/ui/text/progress_tracker.rb.ut.rb +34 -0
  423. data/lib/rex/ui/text/shell.rb +328 -0
  424. data/lib/rex/ui/text/table.rb +279 -0
  425. data/lib/rex/ui/text/table.rb.ut.rb +55 -0
  426. data/lib/rex/zip.rb +93 -0
  427. data/lib/rex/zip/archive.rb +184 -0
  428. data/lib/rex/zip/blocks.rb +182 -0
  429. data/lib/rex/zip/entry.rb +104 -0
  430. data/lib/rex/zip/samples/comment.rb +32 -0
  431. data/lib/rex/zip/samples/mkwar.rb +138 -0
  432. data/lib/rex/zip/samples/mkzip.rb +19 -0
  433. data/lib/rex/zip/samples/recursive.rb +58 -0
  434. 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