librex 0.0.1

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