librex 0.0.68 → 0.0.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. checksums.yaml +15 -0
  2. data/README.markdown +1 -1
  3. data/Rakefile +18 -16
  4. data/lib/rex.rb +14 -10
  5. data/lib/rex/LICENSE +2 -2
  6. data/lib/rex/arch.rb +76 -76
  7. data/lib/rex/arch/sparc.rb +57 -58
  8. data/lib/rex/arch/x86.rb +506 -496
  9. data/lib/rex/assembly/nasm.rb +83 -84
  10. data/lib/rex/compat.rb +228 -173
  11. data/lib/rex/constants.rb +47 -37
  12. data/lib/rex/elfparsey.rb +0 -3
  13. data/lib/rex/elfparsey/elf.rb +107 -110
  14. data/lib/rex/elfparsey/elfbase.rb +244 -247
  15. data/lib/rex/elfparsey/exceptions.rb +0 -3
  16. data/lib/rex/elfscan.rb +0 -3
  17. data/lib/rex/elfscan/scanner.rb +184 -166
  18. data/lib/rex/elfscan/search.rb +35 -38
  19. data/lib/rex/encoder/alpha2.rb +1 -2
  20. data/lib/rex/encoder/alpha2/alpha_mixed.rb +52 -53
  21. data/lib/rex/encoder/alpha2/alpha_upper.rb +62 -63
  22. data/lib/rex/encoder/alpha2/generic.rb +77 -78
  23. data/lib/rex/encoder/alpha2/unicode_mixed.rb +101 -97
  24. data/lib/rex/encoder/alpha2/unicode_upper.rb +106 -107
  25. data/lib/rex/encoder/bloxor/bloxor.rb +326 -0
  26. data/lib/rex/encoder/ndr.rb +68 -68
  27. data/lib/rex/encoder/nonalpha.rb +50 -51
  28. data/lib/rex/encoder/nonupper.rb +50 -51
  29. data/lib/rex/encoder/xdr.rb +78 -78
  30. data/lib/rex/encoder/xor.rb +52 -53
  31. data/lib/rex/encoder/xor/dword.rb +1 -2
  32. data/lib/rex/encoder/xor/dword_additive.rb +1 -2
  33. data/lib/rex/encoders/xor_dword.rb +17 -18
  34. data/lib/rex/encoders/xor_dword_additive.rb +35 -36
  35. data/lib/rex/encoding/xor.rb +0 -1
  36. data/lib/rex/encoding/xor/byte.rb +3 -4
  37. data/lib/rex/encoding/xor/dword.rb +3 -4
  38. data/lib/rex/encoding/xor/dword_additive.rb +72 -73
  39. data/lib/rex/encoding/xor/exceptions.rb +2 -3
  40. data/lib/rex/encoding/xor/generic.rb +129 -130
  41. data/lib/rex/encoding/xor/qword.rb +3 -4
  42. data/lib/rex/encoding/xor/word.rb +3 -4
  43. data/lib/rex/exceptions.rb +100 -101
  44. data/lib/rex/exploitation/cmdstager.rb +3 -3
  45. data/lib/rex/exploitation/cmdstager/base.rb +170 -156
  46. data/lib/rex/exploitation/cmdstager/bourne.rb +105 -0
  47. data/lib/rex/exploitation/cmdstager/debug_asm.rb +110 -113
  48. data/lib/rex/exploitation/cmdstager/debug_write.rb +106 -109
  49. data/lib/rex/exploitation/cmdstager/echo.rb +164 -0
  50. data/lib/rex/exploitation/cmdstager/printf.rb +122 -0
  51. data/lib/rex/exploitation/cmdstager/tftp.rb +34 -27
  52. data/lib/rex/exploitation/cmdstager/vbs.rb +95 -98
  53. data/lib/rex/exploitation/egghunter.rb +359 -346
  54. data/lib/rex/exploitation/encryptjs.rb +60 -60
  55. data/lib/rex/exploitation/heaplib.rb +76 -76
  56. data/lib/rex/exploitation/js.rb +6 -0
  57. data/lib/rex/exploitation/js/detect.rb +69 -0
  58. data/lib/rex/exploitation/js/memory.rb +81 -0
  59. data/lib/rex/exploitation/js/network.rb +84 -0
  60. data/lib/rex/exploitation/js/utils.rb +33 -0
  61. data/lib/rex/exploitation/jsobfu.rb +448 -424
  62. data/lib/rex/exploitation/obfuscatejs.rb +301 -301
  63. data/lib/rex/exploitation/omelet.rb +257 -257
  64. data/lib/rex/exploitation/opcodedb.rb +699 -699
  65. data/lib/rex/exploitation/ropdb.rb +189 -0
  66. data/lib/rex/exploitation/seh.rb +68 -68
  67. data/lib/rex/file.rb +96 -49
  68. data/lib/rex/image_source.rb +0 -3
  69. data/lib/rex/image_source/disk.rb +45 -48
  70. data/lib/rex/image_source/image_source.rb +33 -36
  71. data/lib/rex/image_source/memory.rb +17 -20
  72. data/lib/rex/io/bidirectional_pipe.rb +118 -115
  73. data/lib/rex/io/datagram_abstraction.rb +13 -14
  74. data/lib/rex/io/ring_buffer.rb +273 -273
  75. data/lib/rex/io/stream.rb +284 -284
  76. data/lib/rex/io/stream_abstraction.rb +183 -181
  77. data/lib/rex/io/stream_server.rb +193 -193
  78. data/lib/rex/job_container.rb +167 -167
  79. data/lib/rex/logging.rb +0 -1
  80. data/lib/rex/logging/log_dispatcher.rb +113 -113
  81. data/lib/rex/logging/log_sink.rb +17 -17
  82. data/lib/rex/logging/sinks/flatfile.rb +36 -36
  83. data/lib/rex/logging/sinks/stderr.rb +27 -27
  84. data/lib/rex/mac_oui.rb +16572 -16571
  85. data/lib/rex/machparsey.rb +0 -1
  86. data/lib/rex/machparsey/exceptions.rb +0 -1
  87. data/lib/rex/machparsey/mach.rb +160 -161
  88. data/lib/rex/machparsey/machbase.rb +367 -368
  89. data/lib/rex/machscan.rb +0 -1
  90. data/lib/rex/machscan/scanner.rb +175 -176
  91. data/lib/rex/mime/encoding.rb +17 -0
  92. data/lib/rex/mime/header.rb +58 -58
  93. data/lib/rex/mime/message.rb +140 -137
  94. data/lib/rex/mime/part.rb +41 -12
  95. data/lib/rex/nop/opty2.rb +90 -90
  96. data/lib/rex/nop/opty2_tables.rb +273 -273
  97. data/lib/rex/ole.rb +0 -4
  98. data/lib/rex/ole/clsid.rb +26 -30
  99. data/lib/rex/ole/difat.rb +121 -125
  100. data/lib/rex/ole/directory.rb +205 -209
  101. data/lib/rex/ole/direntry.rb +217 -221
  102. data/lib/rex/ole/fat.rb +79 -83
  103. data/lib/rex/ole/header.rb +178 -182
  104. data/lib/rex/ole/minifat.rb +49 -53
  105. data/lib/rex/ole/propset.rb +113 -117
  106. data/lib/rex/ole/samples/create_ole.rb +8 -9
  107. data/lib/rex/ole/samples/dir.rb +10 -11
  108. data/lib/rex/ole/samples/dump_stream.rb +14 -15
  109. data/lib/rex/ole/samples/ole_info.rb +5 -6
  110. data/lib/rex/ole/storage.rb +372 -376
  111. data/lib/rex/ole/stream.rb +33 -37
  112. data/lib/rex/ole/substorage.rb +20 -24
  113. data/lib/rex/ole/util.rb +137 -141
  114. data/lib/rex/parser/acunetix_nokogiri.rb +398 -398
  115. data/lib/rex/parser/apple_backup_manifestdb.rb +116 -116
  116. data/lib/rex/parser/appscan_nokogiri.rb +359 -359
  117. data/lib/rex/parser/arguments.rb +88 -88
  118. data/lib/rex/parser/burp_session_nokogiri.rb +258 -258
  119. data/lib/rex/parser/ci_nokogiri.rb +184 -184
  120. data/lib/rex/parser/foundstone_nokogiri.rb +334 -333
  121. data/lib/rex/parser/fusionvm_nokogiri.rb +94 -94
  122. data/lib/rex/parser/ini.rb +167 -167
  123. data/lib/rex/parser/ip360_aspl_xml.rb +84 -84
  124. data/lib/rex/parser/ip360_xml.rb +77 -77
  125. data/lib/rex/parser/mbsa_nokogiri.rb +224 -224
  126. data/lib/rex/parser/nessus_xml.rb +100 -100
  127. data/lib/rex/parser/netsparker_xml.rb +89 -75
  128. data/lib/rex/parser/nexpose_raw_nokogiri.rb +677 -677
  129. data/lib/rex/parser/nexpose_simple_nokogiri.rb +322 -322
  130. data/lib/rex/parser/nexpose_xml.rb +105 -105
  131. data/lib/rex/parser/nmap_nokogiri.rb +386 -386
  132. data/lib/rex/parser/nmap_xml.rb +116 -116
  133. data/lib/rex/parser/nokogiri_doc_mixin.rb +223 -221
  134. data/lib/rex/parser/openvas_nokogiri.rb +162 -162
  135. data/lib/rex/parser/outpost24_nokogiri.rb +239 -0
  136. data/lib/rex/parser/retina_xml.rb +90 -90
  137. data/lib/rex/parser/unattend.rb +171 -0
  138. data/lib/rex/parser/wapiti_nokogiri.rb +89 -89
  139. data/lib/rex/payloads/win32/common.rb +14 -14
  140. data/lib/rex/payloads/win32/kernel.rb +36 -36
  141. data/lib/rex/payloads/win32/kernel/common.rb +32 -32
  142. data/lib/rex/payloads/win32/kernel/recovery.rb +27 -27
  143. data/lib/rex/payloads/win32/kernel/stager.rb +170 -170
  144. data/lib/rex/peparsey.rb +0 -3
  145. data/lib/rex/peparsey/exceptions.rb +0 -3
  146. data/lib/rex/peparsey/pe.rb +196 -199
  147. data/lib/rex/peparsey/pe_memdump.rb +35 -38
  148. data/lib/rex/peparsey/pebase.rb +1633 -1652
  149. data/lib/rex/peparsey/section.rb +115 -124
  150. data/lib/rex/pescan.rb +0 -3
  151. data/lib/rex/pescan/analyze.rb +351 -351
  152. data/lib/rex/pescan/scanner.rb +182 -182
  153. data/lib/rex/pescan/search.rb +59 -59
  154. data/lib/rex/platforms/windows.rb +37 -37
  155. data/lib/rex/poly.rb +111 -110
  156. data/lib/rex/poly/block.rb +419 -417
  157. data/lib/rex/poly/machine.rb +12 -0
  158. data/lib/rex/poly/machine/machine.rb +829 -0
  159. data/lib/rex/poly/machine/x86.rb +508 -0
  160. data/lib/rex/poly/register.rb +70 -70
  161. data/lib/rex/poly/register/x86.rb +22 -22
  162. data/lib/rex/post.rb +0 -1
  163. data/lib/rex/post/dir.rb +35 -36
  164. data/lib/rex/post/file.rb +140 -141
  165. data/lib/rex/post/file_stat.rb +198 -199
  166. data/lib/rex/post/io.rb +167 -168
  167. data/lib/rex/post/meterpreter.rb +1 -1
  168. data/lib/rex/post/meterpreter/channel.rb +389 -390
  169. data/lib/rex/post/meterpreter/channel_container.rb +33 -34
  170. data/lib/rex/post/meterpreter/channels/pool.rb +129 -130
  171. data/lib/rex/post/meterpreter/channels/pools/file.rb +35 -36
  172. data/lib/rex/post/meterpreter/channels/pools/stream_pool.rb +72 -73
  173. data/lib/rex/post/meterpreter/channels/stream.rb +62 -63
  174. data/lib/rex/post/meterpreter/client.rb +442 -436
  175. data/lib/rex/post/meterpreter/client_core.rb +326 -310
  176. data/lib/rex/post/meterpreter/dependencies.rb +0 -1
  177. data/lib/rex/post/meterpreter/extension.rb +12 -13
  178. data/lib/rex/post/meterpreter/extensions/espia/espia.rb +35 -36
  179. data/lib/rex/post/meterpreter/extensions/extapi/adsi/adsi.rb +71 -0
  180. data/lib/rex/post/meterpreter/extensions/extapi/clipboard/clipboard.rb +169 -0
  181. data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +45 -0
  182. data/lib/rex/post/meterpreter/extensions/extapi/service/service.rb +104 -0
  183. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +77 -0
  184. data/lib/rex/post/meterpreter/extensions/extapi/window/window.rb +56 -0
  185. data/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb +75 -0
  186. data/lib/rex/post/meterpreter/extensions/incognito/incognito.rb +70 -71
  187. data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +361 -0
  188. data/lib/rex/post/meterpreter/extensions/kiwi/tlv.rb +76 -0
  189. data/lib/rex/post/meterpreter/extensions/lanattacks/dhcp/dhcp.rb +78 -0
  190. data/lib/rex/post/meterpreter/extensions/lanattacks/lanattacks.rb +22 -78
  191. data/lib/rex/post/meterpreter/extensions/lanattacks/tftp/tftp.rb +49 -0
  192. data/lib/rex/post/meterpreter/extensions/lanattacks/tlv.rb +4 -4
  193. data/lib/rex/post/meterpreter/extensions/mimikatz/mimikatz.rb +128 -0
  194. data/lib/rex/post/meterpreter/extensions/mimikatz/tlv.rb +16 -0
  195. data/lib/rex/post/meterpreter/extensions/networkpug/networkpug.rb +38 -39
  196. data/lib/rex/post/meterpreter/extensions/networkpug/tlv.rb +1 -1
  197. data/lib/rex/post/meterpreter/extensions/priv/fs.rb +95 -96
  198. data/lib/rex/post/meterpreter/extensions/priv/passwd.rb +39 -40
  199. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +80 -85
  200. data/lib/rex/post/meterpreter/extensions/sniffer/sniffer.rb +94 -95
  201. data/lib/rex/post/meterpreter/extensions/stdapi/constants.rb +207 -147
  202. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +258 -259
  203. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +366 -301
  204. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file_stat.rb +72 -73
  205. data/lib/rex/post/meterpreter/extensions/stdapi/fs/io.rb +24 -25
  206. data/lib/rex/post/meterpreter/extensions/stdapi/net/arp.rb +59 -0
  207. data/lib/rex/post/meterpreter/extensions/stdapi/net/config.rb +227 -149
  208. data/lib/rex/post/meterpreter/extensions/stdapi/net/interface.rb +107 -108
  209. data/lib/rex/post/meterpreter/extensions/stdapi/net/netstat.rb +97 -0
  210. data/lib/rex/post/meterpreter/extensions/stdapi/net/resolve.rb +106 -0
  211. data/lib/rex/post/meterpreter/extensions/stdapi/net/route.rb +41 -42
  212. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket.rb +102 -101
  213. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_client_channel.rb +151 -152
  214. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +142 -142
  215. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb +185 -185
  216. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb +38118 -38117
  217. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +7 -7
  218. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +2086 -2084
  219. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_crypt32.rb +15 -15
  220. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_iphlpapi.rb +80 -80
  221. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3835 -3833
  222. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +84 -28
  223. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ntdll.rb +151 -137
  224. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_shell32.rb +15 -6
  225. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_user32.rb +3155 -3155
  226. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_version.rb +41 -0
  227. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wlanapi.rb +70 -70
  228. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_wldap32.rb +128 -0
  229. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_ws2_32.rb +596 -596
  230. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb +310 -301
  231. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +71 -61
  232. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +100 -100
  233. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb +14 -14
  234. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/mock_magic.rb +488 -488
  235. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +273 -264
  236. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/platform_util.rb +5 -5
  237. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +240 -238
  238. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/tlv.rb +17 -15
  239. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb +61 -61
  240. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +654 -635
  241. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +49 -49
  242. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +103 -102
  243. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +98 -68
  244. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +165 -166
  245. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log_subsystem/event_record.rb +16 -17
  246. data/lib/rex/post/meterpreter/extensions/stdapi/sys/power.rb +34 -36
  247. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +363 -364
  248. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/image.rb +102 -103
  249. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/io.rb +28 -29
  250. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/memory.rb +303 -304
  251. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process_subsystem/thread.rb +113 -114
  252. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +260 -261
  253. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +165 -166
  254. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_value.rb +69 -70
  255. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +160 -161
  256. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +143 -144
  257. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +29 -12
  258. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +230 -231
  259. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +181 -44
  260. data/lib/rex/post/meterpreter/inbound_packet_handler.rb +12 -13
  261. data/lib/rex/post/meterpreter/object_aliases.rb +56 -57
  262. data/lib/rex/post/meterpreter/packet.rb +591 -592
  263. data/lib/rex/post/meterpreter/packet_dispatcher.rb +506 -496
  264. data/lib/rex/post/meterpreter/packet_parser.rb +72 -73
  265. data/lib/rex/post/meterpreter/packet_response_waiter.rb +56 -57
  266. data/lib/rex/post/meterpreter/ui/console.rb +112 -112
  267. data/lib/rex/post/meterpreter/ui/console/command_dispatcher.rb +53 -53
  268. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +911 -854
  269. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/espia.rb +86 -86
  270. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi.rb +65 -0
  271. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +198 -0
  272. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/clipboard.rb +444 -0
  273. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/service.rb +199 -0
  274. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/window.rb +118 -0
  275. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/wmi.rb +108 -0
  276. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/incognito.rb +220 -220
  277. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +509 -0
  278. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks.rb +60 -0
  279. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +254 -0
  280. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/tftp.rb +159 -0
  281. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +182 -0
  282. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/networkpug.rb +173 -173
  283. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv.rb +40 -40
  284. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +75 -77
  285. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/passwd.rb +30 -30
  286. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +105 -105
  287. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/sniffer.rb +182 -182
  288. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi.rb +37 -37
  289. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +504 -482
  290. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +401 -330
  291. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +883 -581
  292. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +296 -299
  293. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +320 -153
  294. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +78 -78
  295. data/lib/rex/post/permission.rb +0 -1
  296. data/lib/rex/post/process.rb +39 -40
  297. data/lib/rex/post/thread.rb +41 -42
  298. data/lib/rex/post/ui.rb +35 -36
  299. data/lib/rex/proto/addp.rb +218 -0
  300. data/lib/rex/proto/dcerpc/client.rb +344 -344
  301. data/lib/rex/proto/dcerpc/exceptions.rb +128 -128
  302. data/lib/rex/proto/dcerpc/handle.rb +32 -32
  303. data/lib/rex/proto/dcerpc/ndr.rb +56 -56
  304. data/lib/rex/proto/dcerpc/packet.rb +249 -245
  305. data/lib/rex/proto/dcerpc/response.rb +170 -170
  306. data/lib/rex/proto/dcerpc/uuid.rb +65 -65
  307. data/lib/rex/proto/dcerpc/wdscp.rb +3 -0
  308. data/lib/rex/proto/dcerpc/wdscp/constants.rb +89 -0
  309. data/lib/rex/proto/dcerpc/wdscp/packet.rb +94 -0
  310. data/lib/rex/proto/dhcp.rb +0 -1
  311. data/lib/rex/proto/dhcp/constants.rb +0 -1
  312. data/lib/rex/proto/dhcp/server.rb +303 -304
  313. data/lib/rex/proto/drda/constants.rb +1 -1
  314. data/lib/rex/proto/drda/packet.rb +186 -186
  315. data/lib/rex/proto/drda/utils.rb +104 -104
  316. data/lib/rex/proto/http.rb +1 -0
  317. data/lib/rex/proto/http/client.rb +692 -820
  318. data/lib/rex/proto/http/client_request.rb +472 -0
  319. data/lib/rex/proto/http/handler.rb +25 -25
  320. data/lib/rex/proto/http/handler/erb.rb +104 -104
  321. data/lib/rex/proto/http/handler/proc.rb +37 -37
  322. data/lib/rex/proto/http/header.rb +149 -149
  323. data/lib/rex/proto/http/packet.rb +388 -382
  324. data/lib/rex/proto/http/request.rb +332 -335
  325. data/lib/rex/proto/http/response.rb +132 -72
  326. data/lib/rex/proto/http/server.rb +348 -338
  327. data/lib/rex/proto/iax2/call.rb +310 -310
  328. data/lib/rex/proto/iax2/client.rb +197 -197
  329. data/lib/rex/proto/iax2/codecs/alaw.rb +4 -4
  330. data/lib/rex/proto/iax2/codecs/mulaw.rb +4 -4
  331. data/lib/rex/proto/ipmi.rb +57 -0
  332. data/lib/rex/proto/ipmi/channel_auth_reply.rb +88 -0
  333. data/lib/rex/proto/ipmi/open_session_reply.rb +35 -0
  334. data/lib/rex/proto/ipmi/rakp2.rb +35 -0
  335. data/lib/rex/proto/ipmi/utils.rb +125 -0
  336. data/lib/rex/proto/natpmp.rb +1 -5
  337. data/lib/rex/proto/natpmp/constants.rb +4 -4
  338. data/lib/rex/proto/natpmp/packet.rb +25 -25
  339. data/lib/rex/proto/ntlm/base.rb +271 -271
  340. data/lib/rex/proto/ntlm/constants.rb +61 -61
  341. data/lib/rex/proto/ntlm/crypt.rb +348 -352
  342. data/lib/rex/proto/ntlm/exceptions.rb +3 -3
  343. data/lib/rex/proto/ntlm/message.rb +468 -471
  344. data/lib/rex/proto/ntlm/utils.rb +746 -746
  345. data/lib/rex/proto/pjl.rb +30 -0
  346. data/lib/rex/proto/pjl/client.rb +162 -0
  347. data/lib/rex/proto/proxy/socks4a.rb +440 -440
  348. data/lib/rex/proto/rfb.rb +1 -8
  349. data/lib/rex/proto/rfb/cipher.rb +46 -49
  350. data/lib/rex/proto/rfb/client.rb +179 -182
  351. data/lib/rex/proto/rfb/constants.rb +18 -21
  352. data/lib/rex/proto/smb/client.rb +1954 -1843
  353. data/lib/rex/proto/smb/constants.rb +533 -516
  354. data/lib/rex/proto/smb/crypt.rb +21 -21
  355. data/lib/rex/proto/smb/evasions.rb +43 -43
  356. data/lib/rex/proto/smb/exceptions.rb +791 -791
  357. data/lib/rex/proto/smb/simpleclient.rb +142 -286
  358. data/lib/rex/proto/smb/simpleclient/open_file.rb +106 -0
  359. data/lib/rex/proto/smb/simpleclient/open_pipe.rb +57 -0
  360. data/lib/rex/proto/smb/utils.rb +81 -81
  361. data/lib/rex/proto/sunrpc/client.rb +158 -158
  362. data/lib/rex/proto/tftp.rb +0 -1
  363. data/lib/rex/proto/tftp/client.rb +289 -289
  364. data/lib/rex/proto/tftp/constants.rb +9 -10
  365. data/lib/rex/proto/tftp/server.rb +466 -467
  366. data/lib/rex/random_identifier_generator.rb +176 -0
  367. data/lib/rex/registry.rb +1 -1
  368. data/lib/rex/registry/hive.rb +88 -88
  369. data/lib/rex/registry/lfkey.rb +25 -25
  370. data/lib/rex/registry/nodekey.rb +30 -30
  371. data/lib/rex/registry/regf.rb +10 -10
  372. data/lib/rex/registry/valuekey.rb +43 -43
  373. data/lib/rex/registry/valuelist.rb +13 -13
  374. data/lib/rex/ropbuilder/rop.rb +254 -253
  375. data/lib/rex/script.rb +21 -22
  376. data/lib/rex/script/base.rb +51 -50
  377. data/lib/rex/script/meterpreter.rb +2 -2
  378. data/lib/rex/service.rb +24 -24
  379. data/lib/rex/service_manager.rb +132 -132
  380. data/lib/rex/services/local_relay.rb +398 -398
  381. data/lib/rex/socket.rb +758 -763
  382. data/lib/rex/socket/comm.rb +95 -95
  383. data/lib/rex/socket/comm/local.rb +507 -440
  384. data/lib/rex/socket/ip.rb +118 -118
  385. data/lib/rex/socket/parameters.rb +351 -350
  386. data/lib/rex/socket/range_walker.rb +445 -368
  387. data/lib/rex/socket/ssl_tcp.rb +323 -317
  388. data/lib/rex/socket/ssl_tcp_server.rb +173 -158
  389. data/lib/rex/socket/subnet_walker.rb +48 -48
  390. data/lib/rex/socket/switch_board.rb +259 -259
  391. data/lib/rex/socket/tcp.rb +58 -56
  392. data/lib/rex/socket/tcp_server.rb +42 -42
  393. data/lib/rex/socket/udp.rb +152 -152
  394. data/lib/rex/sslscan/result.rb +200 -0
  395. data/lib/rex/sslscan/scanner.rb +205 -0
  396. data/lib/rex/struct2.rb +0 -1
  397. data/lib/rex/struct2/c_struct.rb +162 -163
  398. data/lib/rex/struct2/c_struct_template.rb +21 -22
  399. data/lib/rex/struct2/constant.rb +6 -7
  400. data/lib/rex/struct2/element.rb +30 -31
  401. data/lib/rex/struct2/generic.rb +60 -61
  402. data/lib/rex/struct2/restraint.rb +40 -41
  403. data/lib/rex/struct2/s_string.rb +60 -61
  404. data/lib/rex/struct2/s_struct.rb +97 -98
  405. data/lib/rex/sync.rb +0 -1
  406. data/lib/rex/sync/event.rb +62 -72
  407. data/lib/rex/sync/read_write_lock.rb +149 -149
  408. data/lib/rex/sync/ref.rb +42 -42
  409. data/lib/rex/sync/thread_safe.rb +59 -59
  410. data/lib/rex/text.rb +1803 -1315
  411. data/lib/rex/thread_factory.rb +25 -25
  412. data/lib/rex/time.rb +44 -44
  413. data/lib/rex/transformer.rb +91 -91
  414. data/lib/rex/ui/interactive.rb +265 -265
  415. data/lib/rex/ui/output.rb +66 -60
  416. data/lib/rex/ui/progress_tracker.rb +79 -79
  417. data/lib/rex/ui/subscriber.rb +144 -134
  418. data/lib/rex/ui/text/color.rb +76 -76
  419. data/lib/rex/ui/text/dispatcher_shell.rb +512 -505
  420. data/lib/rex/ui/text/input.rb +96 -96
  421. data/lib/rex/ui/text/input/buffer.rb +58 -58
  422. data/lib/rex/ui/text/input/readline.rb +114 -114
  423. data/lib/rex/ui/text/input/socket.rb +77 -77
  424. data/lib/rex/ui/text/input/stdio.rb +24 -24
  425. data/lib/rex/ui/text/irb_shell.rb +45 -41
  426. data/lib/rex/ui/text/output.rb +64 -60
  427. data/lib/rex/ui/text/output/buffer.rb +42 -42
  428. data/lib/rex/ui/text/output/buffer/stdout.rb +25 -0
  429. data/lib/rex/ui/text/output/file.rb +24 -24
  430. data/lib/rex/ui/text/output/socket.rb +24 -24
  431. data/lib/rex/ui/text/output/stdio.rb +29 -29
  432. data/lib/rex/ui/text/output/tee.rb +36 -36
  433. data/lib/rex/ui/text/progress_tracker.rb +37 -37
  434. data/lib/rex/ui/text/shell.rb +371 -361
  435. data/lib/rex/ui/text/table.rb +320 -284
  436. data/lib/rex/zip.rb +0 -1
  437. data/lib/rex/zip/archive.rb +115 -94
  438. data/lib/rex/zip/blocks.rb +101 -100
  439. data/lib/rex/zip/entry.rb +108 -99
  440. data/lib/rex/zip/jar.rb +261 -206
  441. data/lib/rex/zip/samples/comment.rb +1 -2
  442. data/lib/rex/zip/samples/mkwar.rb +12 -13
  443. data/lib/rex/zip/samples/mkzip.rb +1 -2
  444. data/lib/rex/zip/samples/recursive.rb +29 -30
  445. metadata +424 -446
  446. data/lib/rex/arch/sparc.rb.ut.rb +0 -19
  447. data/lib/rex/arch/x86.rb.ut.rb +0 -94
  448. data/lib/rex/assembly/nasm.rb.ut.rb +0 -23
  449. data/lib/rex/encoder/ndr.rb.ut.rb +0 -45
  450. data/lib/rex/encoder/xdr.rb.ut.rb +0 -30
  451. data/lib/rex/encoders/xor_dword_additive.rb.ut.rb +0 -13
  452. data/lib/rex/encoding/xor.rb.ts.rb +0 -15
  453. data/lib/rex/encoding/xor/byte.rb.ut.rb +0 -22
  454. data/lib/rex/encoding/xor/dword.rb.ut.rb +0 -16
  455. data/lib/rex/encoding/xor/dword_additive.rb.ut.rb +0 -16
  456. data/lib/rex/encoding/xor/generic.rb.ut.rb +0 -121
  457. data/lib/rex/encoding/xor/word.rb.ut.rb +0 -14
  458. data/lib/rex/exceptions.rb.ut.rb +0 -45
  459. data/lib/rex/exploitation/egghunter.rb.ut.rb +0 -28
  460. data/lib/rex/exploitation/javascriptosdetect.js +0 -1014
  461. data/lib/rex/exploitation/javascriptosdetect.rb +0 -43
  462. data/lib/rex/exploitation/omelet.rb.ut.rb +0 -27
  463. data/lib/rex/exploitation/opcodedb.rb.ut.rb +0 -280
  464. data/lib/rex/exploitation/seh.rb.ut.rb +0 -20
  465. data/lib/rex/file.rb.ut.rb +0 -17
  466. data/lib/rex/io/ring_buffer.rb.ut.rb +0 -135
  467. data/lib/rex/nop/opty2.rb.ut.rb +0 -24
  468. data/lib/rex/parser/arguments.rb.ut.rb +0 -68
  469. data/lib/rex/parser/ini.rb.ut.rb +0 -30
  470. data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +0 -18
  471. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +0 -39
  472. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb.ut.rb +0 -37
  473. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll.rb.ut.rb +0 -52
  474. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb +0 -43
  475. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +0 -128
  476. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_wrapper.rb.ut.rb +0 -64
  477. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/platform_util.rb.ut.rb +0 -29
  478. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb.ut.rb +0 -155
  479. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/type/pointer_util.rb.ut.rb +0 -128
  480. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb.ut.rb +0 -124
  481. data/lib/rex/proto.rb.ts.rb +0 -9
  482. data/lib/rex/proto/dcerpc.rb.ts.rb +0 -10
  483. data/lib/rex/proto/dcerpc/client.rb.ut.rb +0 -492
  484. data/lib/rex/proto/dcerpc/handle.rb.ut.rb +0 -86
  485. data/lib/rex/proto/dcerpc/ndr.rb.ut.rb +0 -42
  486. data/lib/rex/proto/dcerpc/packet.rb.ut.rb +0 -57
  487. data/lib/rex/proto/dcerpc/response.rb.ut.rb +0 -16
  488. data/lib/rex/proto/dcerpc/uuid.rb.ut.rb +0 -47
  489. data/lib/rex/proto/drda.rb.ts.rb +0 -18
  490. data/lib/rex/proto/drda/constants.rb.ut.rb +0 -24
  491. data/lib/rex/proto/drda/packet.rb.ut.rb +0 -110
  492. data/lib/rex/proto/drda/utils.rb.ut.rb +0 -85
  493. data/lib/rex/proto/http.rb.ts.rb +0 -13
  494. data/lib/rex/proto/http/client.rb.ut.rb +0 -96
  495. data/lib/rex/proto/http/handler/erb.rb.ut.rb +0 -22
  496. data/lib/rex/proto/http/handler/erb.rb.ut.rb.rhtml +0 -1
  497. data/lib/rex/proto/http/handler/proc.rb.ut.rb +0 -25
  498. data/lib/rex/proto/http/header.rb.ut.rb +0 -47
  499. data/lib/rex/proto/http/packet.rb.ut.rb +0 -166
  500. data/lib/rex/proto/http/request.rb.ut.rb +0 -215
  501. data/lib/rex/proto/http/response.rb.ut.rb +0 -150
  502. data/lib/rex/proto/http/server.rb.ut.rb +0 -80
  503. data/lib/rex/proto/ntlm.rb.ut.rb +0 -181
  504. data/lib/rex/proto/rfb.rb.ut.rb +0 -40
  505. data/lib/rex/proto/smb.rb.ts.rb +0 -9
  506. data/lib/rex/proto/smb/client.rb.ut.rb +0 -224
  507. data/lib/rex/proto/smb/constants.rb.ut.rb +0 -19
  508. data/lib/rex/proto/smb/simpleclient.rb.ut.rb +0 -129
  509. data/lib/rex/proto/smb/utils.rb.ut.rb +0 -21
  510. data/lib/rex/proto/tftp/server.rb.ut.rb +0 -29
  511. data/lib/rex/service_manager.rb.ut.rb +0 -33
  512. data/lib/rex/socket.rb.ut.rb +0 -108
  513. data/lib/rex/socket/comm/local.rb.ut.rb +0 -76
  514. data/lib/rex/socket/parameters.rb.ut.rb +0 -52
  515. data/lib/rex/socket/range_walker.rb.ut.rb +0 -56
  516. data/lib/rex/socket/ssl_tcp.rb.ut.rb +0 -40
  517. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +0 -62
  518. data/lib/rex/socket/subnet_walker.rb.ut.rb +0 -29
  519. data/lib/rex/socket/switch_board.rb.ut.rb +0 -53
  520. data/lib/rex/socket/tcp.rb.ut.rb +0 -65
  521. data/lib/rex/socket/tcp_server.rb.ut.rb +0 -45
  522. data/lib/rex/socket/udp.rb.ut.rb +0 -45
  523. data/lib/rex/test.rb +0 -36
  524. data/lib/rex/text.rb.ut.rb +0 -193
  525. data/lib/rex/transformer.rb.ut.rb +0 -39
  526. data/lib/rex/ui/text/color.rb.ut.rb +0 -19
  527. data/lib/rex/ui/text/progress_tracker.rb.ut.rb +0 -35
  528. data/lib/rex/ui/text/table.rb.ut.rb +0 -56
@@ -14,69 +14,69 @@ module Ui
14
14
  ###
15
15
  module Console::CommandDispatcher
16
16
 
17
- include Rex::Ui::Text::DispatcherShell::CommandDispatcher
17
+ include Rex::Ui::Text::DispatcherShell::CommandDispatcher
18
18
 
19
- #
20
- # The hash of file names to class names after a module has already been
21
- # loaded once on the client side.
22
- #
23
- @@file_hash = {}
19
+ #
20
+ # The hash of file names to class names after a module has already been
21
+ # loaded once on the client side.
22
+ #
23
+ @@file_hash = {}
24
24
 
25
- #
26
- # Checks the file name to hash association to see if the module being
27
- # requested has already been loaded once.
28
- #
29
- def self.check_hash(name)
30
- @@file_hash[name]
31
- end
25
+ #
26
+ # Checks the file name to hash association to see if the module being
27
+ # requested has already been loaded once.
28
+ #
29
+ def self.check_hash(name)
30
+ @@file_hash[name]
31
+ end
32
32
 
33
- #
34
- # Sets the file path to class name association for future reference.
35
- #
36
- def self.set_hash(name, klass)
37
- @@file_hash[name] = klass
38
- end
33
+ #
34
+ # Sets the file path to class name association for future reference.
35
+ #
36
+ def self.set_hash(name, klass)
37
+ @@file_hash[name] = klass
38
+ end
39
39
 
40
- def initialize(shell)
41
- @msf_loaded = nil
42
- super
43
- end
40
+ def initialize(shell)
41
+ @msf_loaded = nil
42
+ super
43
+ end
44
44
 
45
- #
46
- # Returns the meterpreter client context.
47
- #
48
- def client
49
- shell.client
50
- end
45
+ #
46
+ # Returns the meterpreter client context.
47
+ #
48
+ def client
49
+ shell.client
50
+ end
51
51
 
52
- #
53
- # Returns true if the client has a framework object.
54
- #
55
- # Used for firing framework session events
56
- #
57
- def msf_loaded?
58
- return @msf_loaded unless @msf_loaded.nil?
59
- # if we get here we must not have initialized yet
52
+ #
53
+ # Returns true if the client has a framework object.
54
+ #
55
+ # Used for firing framework session events
56
+ #
57
+ def msf_loaded?
58
+ return @msf_loaded unless @msf_loaded.nil?
59
+ # if we get here we must not have initialized yet
60
60
 
61
- if client.framework
62
- # We have a framework instance so the msf libraries should be
63
- # available. Load up the ones we're going to use
64
- require 'msf/base/serializer/readable_text'
65
- end
66
- @msf_loaded = !!(client.framework)
67
- @msf_loaded
68
- end
61
+ if client.framework
62
+ # We have a framework instance so the msf libraries should be
63
+ # available. Load up the ones we're going to use
64
+ require 'msf/base/serializer/readable_text'
65
+ end
66
+ @msf_loaded = !!(client.framework)
67
+ @msf_loaded
68
+ end
69
69
 
70
- #
71
- # Log that an error occurred.
72
- #
73
- def log_error(msg)
74
- print_error(msg)
70
+ #
71
+ # Log that an error occurred.
72
+ #
73
+ def log_error(msg)
74
+ print_error(msg)
75
75
 
76
- elog(msg, 'meterpreter')
76
+ elog(msg, 'meterpreter')
77
77
 
78
- dlog("Call stack:\n#{$@.join("\n")}", 'meterpreter')
79
- end
78
+ dlog("Call stack:\n#{$@.join("\n")}", 'meterpreter')
79
+ end
80
80
 
81
81
  end
82
82
 
@@ -1,4 +1,5 @@
1
1
  # -*- coding: binary -*-
2
+ require 'set'
2
3
  require 'rex/post/meterpreter'
3
4
  require 'rex/parser/arguments'
4
5
 
@@ -15,863 +16,919 @@ module Ui
15
16
  ###
16
17
  class Console::CommandDispatcher::Core
17
18
 
18
- include Console::CommandDispatcher
19
-
20
- #
21
- # Initializes an instance of the core command set using the supplied shell
22
- # for interactivity.
23
- #
24
- def initialize(shell)
25
- super
26
-
27
- self.extensions = []
28
- self.bgjobs = []
29
- self.bgjob_id = 0
30
-
31
- end
32
-
33
- @@load_opts = Rex::Parser::Arguments.new(
34
- "-l" => [ false, "List all available extensions" ],
35
- "-h" => [ false, "Help menu." ])
36
-
37
- #
38
- # List of supported commands.
39
- #
40
- def commands
41
- c = {
42
- "?" => "Help menu",
43
- "background" => "Backgrounds the current session",
44
- "close" => "Closes a channel",
45
- "channel" => "Displays information about active channels",
46
- "exit" => "Terminate the meterpreter session",
47
- "help" => "Help menu",
48
- "interact" => "Interacts with a channel",
49
- "irb" => "Drop into irb scripting mode",
50
- "use" => "Deprecated alias for 'load'",
51
- "load" => "Load one or more meterpreter extensions",
52
- "quit" => "Terminate the meterpreter session",
53
- "resource" => "Run the commands stored in a file",
54
- "read" => "Reads data from a channel",
55
- "run" => "Executes a meterpreter script or Post module",
56
- "bgrun" => "Executes a meterpreter script as a background thread",
57
- "bgkill" => "Kills a background meterpreter script",
58
- "bglist" => "Lists running background scripts",
59
- "write" => "Writes data to a channel",
60
- "enable_unicode_encoding" => "Enables encoding of unicode strings",
61
- "disable_unicode_encoding" => "Disables encoding of unicode strings"
62
- }
63
-
64
- if client.passive_service
65
- c["detach"] = "Detach the meterpreter session (for http/https)"
66
- end
67
- # The only meterp that implements this right now is native Windows and for
68
- # whatever reason it is not adding core_migrate to its list of commands.
69
- # Use a dumb platform til it gets sorted.
70
- #if client.commands.include? "core_migrate"
71
- if client.platform =~ /win/
72
- c["migrate"] = "Migrate the server to another process"
73
- end
74
-
75
- if (msf_loaded?)
76
- c["info"] = "Displays information about a Post module"
77
- end
78
-
79
- c
80
- end
81
-
82
- #
83
- # Core baby.
84
- #
85
- def name
86
- "Core"
87
- end
88
-
89
- def cmd_background_help
90
- print_line "Usage: background"
91
- print_line
92
- print_line "Stop interacting with this session and return to the parent prompt"
93
- print_line
94
- end
95
-
96
- def cmd_background
97
- print_status "Backgrounding session #{client.name}..."
98
- client.interacting = false
99
- end
100
-
101
- #
102
- # Displays information about active channels
103
- #
104
- @@channel_opts = Rex::Parser::Arguments.new(
105
- "-c" => [ true, "Close the given channel." ],
106
- "-k" => [ true, "Close the given channel." ],
107
- "-i" => [ true, "Interact with the given channel." ],
108
- "-l" => [ false, "List active channels." ],
109
- "-r" => [ true, "Read from the given channel." ],
110
- "-w" => [ true, "Write to the given channel." ],
111
- "-h" => [ false, "Help menu." ])
112
-
113
- def cmd_channel_help
114
- print_line "Usage: channel [options]"
115
- print_line
116
- print_line "Displays information about active channels."
117
- print_line @@channel_opts.usage
118
- end
119
-
120
- #
121
- # Performs operations on the supplied channel.
122
- #
123
- def cmd_channel(*args)
124
- if args.empty? or args.include?("-h") or args.include?("--help")
125
- cmd_channel_help
126
- return
127
- end
128
-
129
- mode = nil
130
- chan = nil
131
- data = []
132
-
133
- # Parse options
134
- @@channel_opts.parse(args) { |opt, idx, val|
135
- case opt
136
- when "-l"
137
- mode = :list
138
- when "-c", "-k"
139
- mode = :close
140
- chan = val
141
- when "-i"
142
- mode = :interact
143
- chan = val
144
- when "-r"
145
- mode = :read
146
- chan = val
147
- when "-w"
148
- mode = :write
149
- chan = val
150
- end
151
- if @@channel_opts.arg_required?(opt)
152
- unless chan
153
- print_error("Channel ID required")
154
- return
155
- end
156
- end
157
- }
158
-
159
- case mode
160
- when :list
161
- tbl = Rex::Ui::Text::Table.new(
162
- 'Indent' => 4,
163
- 'Columns' =>
164
- [
165
- 'Id',
166
- 'Class',
167
- 'Type'
168
- ])
169
- items = 0
170
-
171
- client.channels.each_pair { |cid, channel|
172
- tbl << [ cid, channel.class.cls, channel.type ]
173
- items += 1
174
- }
175
-
176
- if (items == 0)
177
- print_line("No active channels.")
178
- else
179
- print("\n" + tbl.to_s + "\n")
180
- end
181
- when :close
182
- cmd_close(chan)
183
- when :interact
184
- cmd_interact(chan)
185
- when :read
186
- cmd_read(chan)
187
- when :write
188
- cmd_write(chan)
189
- else
190
- # No mode, no service.
191
- return true
192
- end
193
- end
194
-
195
- def cmd_channel_tabs(str, words)
196
- case words.length
197
- when 1
198
- @@channel_opts.fmt.keys
199
- when 2
200
- case words[1]
201
- when "-k", "-c", "-i", "-r", "-w"
202
- tab_complete_channels
203
- else
204
- []
205
- end
206
- else
207
- []
208
- end
209
- end
210
-
211
- def cmd_close_help
212
- print_line "Usage: close <channel_id>"
213
- print_line
214
- print_line "Closes the supplied channel."
215
- print_line
216
- end
217
-
218
- #
219
- # Closes a supplied channel.
220
- #
221
- def cmd_close(*args)
222
- if (args.length == 0)
223
- cmd_close_help
224
- return true
225
- end
226
-
227
- cid = args[0].to_i
228
- channel = client.find_channel(cid)
229
-
230
- if (!channel)
231
- print_error("Invalid channel identifier specified.")
232
- return true
233
- else
234
- channel._close # Issue #410
235
-
236
- print_status("Closed channel #{cid}.")
237
- end
238
- end
239
-
240
- def cmd_close_tabs(str, words)
241
- return [] if words.length > 1
242
-
243
- return tab_complete_channels
244
- end
245
-
246
- #
247
- # Terminates the meterpreter session.
248
- #
249
- def cmd_exit(*args)
250
- print_status("Shutting down Meterpreter...")
251
- client.core.shutdown rescue nil
252
- client.shutdown_passive_dispatcher
253
- shell.stop
254
- end
255
-
256
- alias cmd_quit cmd_exit
257
-
258
- def cmd_detach_help
259
- print_line "Detach from the victim. Only possible for non-stream sessions (http/https)"
260
- print_line
261
- print_line "The victim will continue to attempt to call back to the handler until it"
262
- print_line "successfully connects (which may happen immediately if you have a handler"
263
- print_line "running in the background), or reaches its expiration."
264
- print_line
265
- print_line "This session may #{client.passive_service ? "" : "NOT"} be detached."
266
- print_line
267
- end
268
-
269
- #
270
- # Disconnects the session
271
- #
272
- def cmd_detach(*args)
273
- if not client.passive_service
274
- print_error("Detach is only possible for non-stream sessions (http/https)")
275
- return
276
- end
277
- client.shutdown_passive_dispatcher
278
- shell.stop
279
- end
280
-
281
- def cmd_interact_help
282
- print_line "Usage: interact <channel_id>"
283
- print_line
284
- print_line "Interacts with the supplied channel."
285
- print_line
286
- end
287
-
288
- #
289
- # Interacts with a channel.
290
- #
291
- def cmd_interact(*args)
292
- if (args.length == 0)
293
- cmd_info_help
294
- return true
295
- end
296
-
297
- cid = args[0].to_i
298
- channel = client.find_channel(cid)
299
-
300
- if (channel)
301
- print_line("Interacting with channel #{cid}...\n")
302
-
303
- shell.interact_with_channel(channel)
304
- else
305
- print_error("Invalid channel identifier specified.")
306
- end
307
- end
308
-
309
- alias cmd_interact_tabs cmd_close_tabs
310
-
311
- #
312
- # Runs the IRB scripting shell
313
- #
314
- def cmd_irb(*args)
315
- print_status("Starting IRB shell")
316
- print_status("The 'client' variable holds the meterpreter client\n")
317
-
318
- Rex::Ui::Text::IrbShell.new(binding).run
319
- end
320
-
321
- def cmd_migrate_help
322
- print_line "Usage: migrate <pid>"
323
- print_line
324
- print_line "Migrates the server instance to another process."
325
- print_line "NOTE: Any open channels or other dynamic state will be lost."
326
- print_line
327
- end
328
-
329
- #
330
- # Migrates the server to the supplied process identifier.
331
- #
332
- def cmd_migrate(*args)
333
- if (args.length == 0)
334
- cmd_migrate_help
335
- return true
336
- end
337
-
338
- pid = args[0].to_i
339
- if(pid == 0)
340
- print_error("A process ID must be specified, not a process name")
341
- return
342
- end
343
-
344
- print_status("Migrating to #{pid}...")
345
-
346
- # Do this thang.
347
- client.core.migrate(pid)
348
-
349
- print_status("Migration completed successfully.")
350
- end
351
-
352
- def cmd_load_help
353
- print_line("Usage: load ext1 ext2 ext3 ...")
354
- print_line
355
- print_line "Loads a meterpreter extension module or modules."
356
- print_line @@load_opts.usage
357
- end
358
-
359
- #
360
- # Loads one or more meterpreter extensions.
361
- #
362
- def cmd_load(*args)
363
- if (args.length == 0)
364
- args.unshift("-h")
365
- end
366
-
367
- modules = nil
368
-
369
- @@load_opts.parse(args) { |opt, idx, val|
370
- case opt
371
- when "-l"
372
- exts = []
373
- path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter')
374
- ::Dir.entries(path).each { |f|
375
- if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
376
- exts.push($1)
377
- end
378
- }
379
- print(exts.sort.join("\n") + "\n")
380
-
381
- return true
382
- when "-h"
383
- cmd_load_help
384
- return true
385
- end
386
- }
387
-
388
- # Load each of the modules
389
- args.each { |m|
390
- md = m.downcase
391
-
392
- if (extensions.include?(md))
393
- print_error("The '#{md}' extension has already been loaded.")
394
- next
395
- end
396
-
397
- print("Loading extension #{md}...")
398
-
399
- begin
400
- # Use the remote side, then load the client-side
401
- if (client.core.use(md) == true)
402
- add_extension_client(md)
403
- end
404
- rescue
405
- print_line
406
- log_error("Failed to load extension: #{$!}")
407
- next
408
- end
409
-
410
- print_line("success.")
411
- }
412
-
413
- return true
414
- end
415
-
416
- def cmd_load_tabs(str, words)
417
- tabs = []
418
- path = ::File.join(Msf::Config.install_root, 'data', 'meterpreter')
419
- ::Dir.entries(path).each { |f|
420
- if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
421
- if (not extensions.include?($1))
422
- tabs.push($1)
423
- end
424
- end
425
- }
426
- return tabs
427
- end
428
-
429
- def cmd_use(*args)
430
- #print_error("Warning: The 'use' command is deprecated in favor of 'load'")
431
- cmd_load(*args)
432
- end
433
- alias cmd_use_help cmd_load_help
434
- alias cmd_use_tabs cmd_load_tabs
435
-
436
- def cmd_read_help
437
- print_line "Usage: read <channel_id> [length]"
438
- print_line
439
- print_line "Reads data from the supplied channel."
440
- print_line
441
- end
442
-
443
- #
444
- # Reads data from a channel.
445
- #
446
- def cmd_read(*args)
447
- if (args.length == 0)
448
- cmd_read_help
449
- return true
450
- end
451
-
452
- cid = args[0].to_i
453
- length = (args.length >= 2) ? args[1].to_i : 16384
454
- channel = client.find_channel(cid)
455
-
456
- if (!channel)
457
- print_error("Channel #{cid} is not valid.")
458
- return true
459
- end
460
-
461
- data = channel.read(length)
462
-
463
- if (data and data.length)
464
- print("Read #{data.length} bytes from #{cid}:\n\n#{data}\n")
465
- else
466
- print_error("No data was returned.")
467
- end
468
-
469
- return true
470
- end
471
-
472
- alias cmd_read_tabs cmd_close_tabs
473
-
474
- def cmd_run_help
475
- print_line "Usage: run <script> [arguments]"
476
- print_line
477
- print_line "Executes a ruby script or Metasploit Post module in the context of the"
478
- print_line "meterpreter session. Post modules can take arguments in var=val format."
479
- print_line "Example: run post/foo/bar BAZ=abcd"
480
- print_line
481
- end
482
-
483
- #
484
- # Executes a script in the context of the meterpreter session.
485
- #
486
- def cmd_run(*args)
487
- if args.length == 0
488
- cmd_run_help
489
- return true
490
- end
491
-
492
- # Get the script name
493
- begin
494
- script_name = args.shift
495
- # First try it as a Post module if we have access to the Metasploit
496
- # Framework instance. If we don't, or if no such module exists,
497
- # fall back to using the scripting interface.
498
- if (msf_loaded? and mod = client.framework.modules.create(script_name))
499
- omod = mod
500
- mod = client.framework.modules.reload_module(mod)
501
- if (not mod)
502
- print_error("Failed to reload module: #{client.framework.modules.failed[omod.file_path]}")
503
- return
504
- end
505
- opts = (args + [ "SESSION=#{client.sid}" ]).join(',')
506
- mod.run_simple(
507
- #'RunAsJob' => true,
508
- 'LocalInput' => shell.input,
509
- 'LocalOutput' => shell.output,
510
- 'OptionStr' => opts
511
- )
512
- else
513
- # the rest of the arguments get passed in through the binding
514
- client.execute_script(script_name, args)
515
- end
516
- rescue
517
- print_error("Error in script: #{$!.class} #{$!}")
518
- elog("Error in script: #{$!.class} #{$!}")
519
- dlog("Callstack: #{$@.join("\n")}")
520
- end
521
- end
522
-
523
- def cmd_run_tabs(str, words)
524
- tabs = []
525
- if(not words[1] or not words[1].match(/^\//))
526
- begin
527
- if (msf_loaded?)
528
- tabs += tab_complete_postmods
529
- end
530
- [
531
- ::Msf::Sessions::Meterpreter.script_base,
532
- ::Msf::Sessions::Meterpreter.user_script_base
533
- ].each do |dir|
534
- next if not ::File.exist? dir
535
- tabs += ::Dir.new(dir).find_all { |e|
536
- path = dir + ::File::SEPARATOR + e
537
- ::File.file?(path) and ::File.readable?(path)
538
- }
539
- end
540
- rescue Exception
541
- end
542
- end
543
- return tabs.map { |e| e.sub(/\.rb$/, '') }
544
- end
545
-
546
-
547
- #
548
- # Executes a script in the context of the meterpreter session in the background
549
- #
550
- def cmd_bgrun(*args)
551
- if args.length == 0
552
- print_line(
553
- "Usage: bgrun <script> [arguments]\n\n" +
554
- "Executes a ruby script in the context of the meterpreter session.")
555
- return true
556
- end
557
-
558
- jid = self.bgjob_id
559
- self.bgjob_id += 1
560
-
561
- # Get the script name
562
- self.bgjobs[jid] = Rex::ThreadFactory.spawn("MeterpreterBGRun(#{args[0]})-#{jid}", false, jid, args) do |myjid,xargs|
563
- ::Thread.current[:args] = xargs.dup
564
- begin
565
- # the rest of the arguments get passed in through the binding
566
- client.execute_script(args.shift, args)
567
- rescue ::Exception
568
- print_error("Error in script: #{$!.class} #{$!}")
569
- elog("Error in script: #{$!.class} #{$!}")
570
- dlog("Callstack: #{$@.join("\n")}")
571
- end
572
- self.bgjobs[myjid] = nil
573
- print_status("Background script with Job ID #{myjid} has completed (#{::Thread.current[:args].inspect})")
574
- end
575
-
576
- print_status("Executed Meterpreter with Job ID #{jid}")
577
- end
578
-
579
- #
580
- # Map this to the normal run command tab completion
581
- #
582
- def cmd_bgrun_tabs(*args)
583
- cmd_run_tabs(*args)
584
- end
585
-
586
- #
587
- # Kill a background job
588
- #
589
- def cmd_bgkill(*args)
590
- if args.length == 0
591
- print_line("Usage: bgkill [id]")
592
- return
593
- end
594
-
595
- args.each do |jid|
596
- jid = jid.to_i
597
- if self.bgjobs[jid]
598
- print_status("Killing background job #{jid}...")
599
- self.bgjobs[jid].kill
600
- self.bgjobs[jid] = nil
601
- else
602
- print_error("Job #{jid} was not running")
603
- end
604
- end
605
- end
606
-
607
- #
608
- # List background jobs
609
- #
610
- def cmd_bglist(*args)
611
- self.bgjobs.each_index do |jid|
612
- if self.bgjobs[jid]
613
- print_status("Job #{jid}: #{self.bgjobs[jid][:args].inspect}")
614
- end
615
- end
616
- end
617
-
618
- def cmd_info_help
619
- print_line 'Usage: info <module>'
620
- print_line
621
- print_line 'Prints information about a post-exploitation module'
622
- print_line
623
- end
624
-
625
- #
626
- # Show info for a given Post module.
627
- #
628
- # See also +cmd_info+ in lib/msf/ui/console/command_dispatcher/core.rb
629
- #
630
- def cmd_info(*args)
631
- return unless msf_loaded?
632
-
633
- if args.length != 1 or args.include?("-h")
634
- cmd_info_help
635
- return
636
- end
637
-
638
- module_name = args.shift
639
- mod = client.framework.modules.create(module_name);
640
-
641
- if mod.nil?
642
- print_error 'Invalid module: ' << module_name
643
- end
644
-
645
- if (mod)
646
- print_line(::Msf::Serializer::ReadableText.dump_module(mod))
647
- mod_opt = ::Msf::Serializer::ReadableText.dump_options(mod, ' ')
648
- print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if (mod_opt and mod_opt.length > 0)
649
- end
650
- end
651
-
652
- def cmd_info_tabs(*args)
653
- return unless msf_loaded?
654
- tab_complete_postmods
655
- end
656
-
657
- #
658
- # Writes data to a channel.
659
- #
660
- @@write_opts = Rex::Parser::Arguments.new(
661
- "-f" => [ true, "Write the contents of a file on disk" ],
662
- "-h" => [ false, "Help menu." ])
663
-
664
- def cmd_write_help
665
- print_line "Usage: write [options] channel_id"
666
- print_line
667
- print_line "Writes data to the supplied channel."
668
- print_line @@write_opts.usage
669
- end
670
-
671
- def cmd_write(*args)
672
- if (args.length == 0 or args.include?("-h"))
673
- cmd_write_help
674
- return
675
- end
676
-
677
- src_file = nil
678
- cid = nil
679
-
680
- @@write_opts.parse(args) { |opt, idx, val|
681
- case opt
682
- when "-f"
683
- src_file = val
684
- else
685
- cid = val.to_i
686
- end
687
- }
688
-
689
- # Find the channel associated with this cid, assuming the cid is valid.
690
- if ((!cid) or
691
- (!(channel = client.find_channel(cid))))
692
- print_error("Invalid channel identifier specified.")
693
- return true
694
- end
695
-
696
- # If they supplied a source file, read in its contents and write it to
697
- # the channel
698
- if (src_file)
699
- begin
700
- data = ''
701
-
702
- ::File.open(src_file, 'rb') { |f|
703
- data = f.read(f.stat.size)
704
- }
705
-
706
- rescue Errno::ENOENT
707
- print_error("Invalid source file specified: #{src_file}")
708
- return true
709
- end
710
-
711
- if (data and data.length > 0)
712
- channel.write(data)
713
- print_status("Wrote #{data.length} bytes to channel #{cid}.")
714
- else
715
- print_error("No data to send from file #{src_file}")
716
- return true
717
- end
718
- # Otherwise, read from the input descriptor until we're good to go.
719
- else
720
- print("Enter data followed by a '.' on an empty line:\n\n")
721
-
722
- data = ''
723
-
724
- # Keep truckin'
725
- while (s = shell.input.gets)
726
- break if (s =~ /^\.\r?\n?$/)
727
- data += s
728
- end
729
-
730
- if (!data or data.length == 0)
731
- print_error("No data to send.")
732
- else
733
- channel.write(data)
734
- print_status("Wrote #{data.length} bytes to channel #{cid}.")
735
- end
736
- end
737
-
738
- return true
739
- end
740
-
741
- def cmd_resource_help
742
- print_line "Usage: resource <path1> [path2 ...]"
743
- print_line
744
- print_line "Run the commands stored in the supplied files."
745
- print_line
746
- end
747
-
748
- def cmd_resource(*args)
749
- if args.empty?
750
- return false
751
- end
752
- args.each do |glob|
753
- files = ::Dir.glob(::File.expand_path(glob))
754
- if files.empty?
755
- print_error("No such file #{glob}")
756
- next
757
- end
758
- files.each do |filename|
759
- print_status("Reading #{filename}")
760
- if (not ::File.readable?(filename))
761
- print_error("Could not read file #{filename}")
762
- next
763
- else
764
- ::File.open(filename, "r").each_line do |line|
765
- next if line.strip.length < 1
766
- next if line[0,1] == "#"
767
- begin
768
- print_status("Running #{line}")
769
- client.console.run_single(line)
770
- rescue ::Exception => e
771
- print_error("Error Running Command #{line}: #{e.class} #{e}")
772
- end
773
-
774
- end
775
- end
776
- end
777
- end
778
- end
779
-
780
- def cmd_resource_tabs(str, words)
781
- return [] if words.length > 1
782
-
783
- tab_complete_filenames(str, words)
784
- end
785
-
786
- def cmd_enable_unicode_encoding
787
- client.encode_unicode = true
788
- print_status("Unicode encoding is enabled")
789
- end
790
-
791
- def cmd_disable_unicode_encoding
792
- client.encode_unicode = false
793
- print_status("Unicode encoding is disabled")
794
- end
795
-
796
- @@client_extension_search_paths = [ ::File.join(Rex::Root, "post", "meterpreter", "ui", "console", "command_dispatcher") ]
797
-
798
- def self.add_client_extension_search_path(path)
799
- @@client_extension_search_paths << path unless @@client_extension_search_paths.include?(path)
800
- end
801
- def self.client_extension_search_paths
802
- @@client_extension_search_paths
803
- end
19
+ include Console::CommandDispatcher
20
+
21
+ #
22
+ # Initializes an instance of the core command set using the supplied shell
23
+ # for interactivity.
24
+ #
25
+ def initialize(shell)
26
+ super
27
+
28
+ self.extensions = []
29
+ self.bgjobs = []
30
+ self.bgjob_id = 0
31
+
32
+ end
33
+
34
+ @@load_opts = Rex::Parser::Arguments.new(
35
+ "-l" => [ false, "List all available extensions" ],
36
+ "-h" => [ false, "Help menu." ])
37
+
38
+ #
39
+ # List of supported commands.
40
+ #
41
+ def commands
42
+ c = {
43
+ "?" => "Help menu",
44
+ "background" => "Backgrounds the current session",
45
+ "close" => "Closes a channel",
46
+ "channel" => "Displays information about active channels",
47
+ "exit" => "Terminate the meterpreter session",
48
+ "help" => "Help menu",
49
+ "interact" => "Interacts with a channel",
50
+ "irb" => "Drop into irb scripting mode",
51
+ "use" => "Deprecated alias for 'load'",
52
+ "load" => "Load one or more meterpreter extensions",
53
+ "quit" => "Terminate the meterpreter session",
54
+ "resource" => "Run the commands stored in a file",
55
+ "read" => "Reads data from a channel",
56
+ "run" => "Executes a meterpreter script or Post module",
57
+ "bgrun" => "Executes a meterpreter script as a background thread",
58
+ "bgkill" => "Kills a background meterpreter script",
59
+ "bglist" => "Lists running background scripts",
60
+ "write" => "Writes data to a channel",
61
+ "enable_unicode_encoding" => "Enables encoding of unicode strings",
62
+ "disable_unicode_encoding" => "Disables encoding of unicode strings"
63
+ }
64
+
65
+ if client.passive_service
66
+ c["detach"] = "Detach the meterpreter session (for http/https)"
67
+ end
68
+ # The only meterp that implements this right now is native Windows and for
69
+ # whatever reason it is not adding core_migrate to its list of commands.
70
+ # Use a dumb platform til it gets sorted.
71
+ #if client.commands.include? "core_migrate"
72
+ if client.platform =~ /win/
73
+ c["migrate"] = "Migrate the server to another process"
74
+ end
75
+
76
+ if (msf_loaded?)
77
+ c["info"] = "Displays information about a Post module"
78
+ end
79
+
80
+ c
81
+ end
82
+
83
+ #
84
+ # Core baby.
85
+ #
86
+ def name
87
+ "Core"
88
+ end
89
+
90
+ def cmd_background_help
91
+ print_line "Usage: background"
92
+ print_line
93
+ print_line "Stop interacting with this session and return to the parent prompt"
94
+ print_line
95
+ end
96
+
97
+ def cmd_background
98
+ print_status "Backgrounding session #{client.name}..."
99
+ client.interacting = false
100
+ end
101
+
102
+ #
103
+ # Displays information about active channels
104
+ #
105
+ @@channel_opts = Rex::Parser::Arguments.new(
106
+ "-c" => [ true, "Close the given channel." ],
107
+ "-k" => [ true, "Close the given channel." ],
108
+ "-i" => [ true, "Interact with the given channel." ],
109
+ "-l" => [ false, "List active channels." ],
110
+ "-r" => [ true, "Read from the given channel." ],
111
+ "-w" => [ true, "Write to the given channel." ],
112
+ "-h" => [ false, "Help menu." ])
113
+
114
+ def cmd_channel_help
115
+ print_line "Usage: channel [options]"
116
+ print_line
117
+ print_line "Displays information about active channels."
118
+ print_line @@channel_opts.usage
119
+ end
120
+
121
+ #
122
+ # Performs operations on the supplied channel.
123
+ #
124
+ def cmd_channel(*args)
125
+ if args.empty? or args.include?("-h") or args.include?("--help")
126
+ cmd_channel_help
127
+ return
128
+ end
129
+
130
+ mode = nil
131
+ chan = nil
132
+
133
+ # Parse options
134
+ @@channel_opts.parse(args) { |opt, idx, val|
135
+ case opt
136
+ when "-l"
137
+ mode = :list
138
+ when "-c", "-k"
139
+ mode = :close
140
+ chan = val
141
+ when "-i"
142
+ mode = :interact
143
+ chan = val
144
+ when "-r"
145
+ mode = :read
146
+ chan = val
147
+ when "-w"
148
+ mode = :write
149
+ chan = val
150
+ end
151
+ if @@channel_opts.arg_required?(opt)
152
+ unless chan
153
+ print_error("Channel ID required")
154
+ return
155
+ end
156
+ end
157
+ }
158
+
159
+ case mode
160
+ when :list
161
+ tbl = Rex::Ui::Text::Table.new(
162
+ 'Indent' => 4,
163
+ 'Columns' =>
164
+ [
165
+ 'Id',
166
+ 'Class',
167
+ 'Type'
168
+ ])
169
+ items = 0
170
+
171
+ client.channels.each_pair { |cid, channel|
172
+ tbl << [ cid, channel.class.cls, channel.type ]
173
+ items += 1
174
+ }
175
+
176
+ if (items == 0)
177
+ print_line("No active channels.")
178
+ else
179
+ print("\n" + tbl.to_s + "\n")
180
+ end
181
+ when :close
182
+ cmd_close(chan)
183
+ when :interact
184
+ cmd_interact(chan)
185
+ when :read
186
+ cmd_read(chan)
187
+ when :write
188
+ cmd_write(chan)
189
+ else
190
+ # No mode, no service.
191
+ return true
192
+ end
193
+ end
194
+
195
+ def cmd_channel_tabs(str, words)
196
+ case words.length
197
+ when 1
198
+ @@channel_opts.fmt.keys
199
+ when 2
200
+ case words[1]
201
+ when "-k", "-c", "-i", "-r", "-w"
202
+ tab_complete_channels
203
+ else
204
+ []
205
+ end
206
+ else
207
+ []
208
+ end
209
+ end
210
+
211
+ def cmd_close_help
212
+ print_line "Usage: close <channel_id>"
213
+ print_line
214
+ print_line "Closes the supplied channel."
215
+ print_line
216
+ end
217
+
218
+ #
219
+ # Closes a supplied channel.
220
+ #
221
+ def cmd_close(*args)
222
+ if (args.length == 0)
223
+ cmd_close_help
224
+ return true
225
+ end
226
+
227
+ cid = args[0].to_i
228
+ channel = client.find_channel(cid)
229
+
230
+ if (!channel)
231
+ print_error("Invalid channel identifier specified.")
232
+ return true
233
+ else
234
+ channel._close # Issue #410
235
+
236
+ print_status("Closed channel #{cid}.")
237
+ end
238
+ end
239
+
240
+ def cmd_close_tabs(str, words)
241
+ return [] if words.length > 1
242
+
243
+ return tab_complete_channels
244
+ end
245
+
246
+ #
247
+ # Terminates the meterpreter session.
248
+ #
249
+ def cmd_exit(*args)
250
+ print_status("Shutting down Meterpreter...")
251
+ client.core.shutdown rescue nil
252
+ client.shutdown_passive_dispatcher
253
+ shell.stop
254
+ end
255
+
256
+ alias cmd_quit cmd_exit
257
+
258
+ def cmd_detach_help
259
+ print_line "Detach from the victim. Only possible for non-stream sessions (http/https)"
260
+ print_line
261
+ print_line "The victim will continue to attempt to call back to the handler until it"
262
+ print_line "successfully connects (which may happen immediately if you have a handler"
263
+ print_line "running in the background), or reaches its expiration."
264
+ print_line
265
+ print_line "This session may #{client.passive_service ? "" : "NOT"} be detached."
266
+ print_line
267
+ end
268
+
269
+ #
270
+ # Disconnects the session
271
+ #
272
+ def cmd_detach(*args)
273
+ if not client.passive_service
274
+ print_error("Detach is only possible for non-stream sessions (http/https)")
275
+ return
276
+ end
277
+ client.shutdown_passive_dispatcher
278
+ shell.stop
279
+ end
280
+
281
+ def cmd_interact_help
282
+ print_line "Usage: interact <channel_id>"
283
+ print_line
284
+ print_line "Interacts with the supplied channel."
285
+ print_line
286
+ end
287
+
288
+ #
289
+ # Interacts with a channel.
290
+ #
291
+ def cmd_interact(*args)
292
+ if (args.length == 0)
293
+ cmd_info_help
294
+ return true
295
+ end
296
+
297
+ cid = args[0].to_i
298
+ channel = client.find_channel(cid)
299
+
300
+ if (channel)
301
+ print_line("Interacting with channel #{cid}...\n")
302
+
303
+ shell.interact_with_channel(channel)
304
+ else
305
+ print_error("Invalid channel identifier specified.")
306
+ end
307
+ end
308
+
309
+ alias cmd_interact_tabs cmd_close_tabs
310
+
311
+ #
312
+ # Runs the IRB scripting shell
313
+ #
314
+ def cmd_irb(*args)
315
+ print_status("Starting IRB shell")
316
+ print_status("The 'client' variable holds the meterpreter client\n")
317
+
318
+ session = client
319
+ framework = client.framework
320
+ Rex::Ui::Text::IrbShell.new(binding).run
321
+ end
322
+
323
+ def cmd_migrate_help
324
+ print_line "Usage: migrate <pid>"
325
+ print_line
326
+ print_line "Migrates the server instance to another process."
327
+ print_line "NOTE: Any open channels or other dynamic state will be lost."
328
+ print_line
329
+ end
330
+
331
+ #
332
+ # Migrates the server to the supplied process identifier.
333
+ #
334
+ # @param args [Array<String>] Commandline arguments, only -h or a pid
335
+ # @return [void]
336
+ def cmd_migrate(*args)
337
+ if ( args.length == 0 or args.include?("-h") )
338
+ cmd_migrate_help
339
+ return true
340
+ end
341
+
342
+ pid = args[0].to_i
343
+ if(pid == 0)
344
+ print_error("A process ID must be specified, not a process name")
345
+ return
346
+ end
347
+
348
+ begin
349
+ server = client.sys.process.open
350
+ rescue TimeoutError => e
351
+ elog(e.to_s)
352
+ rescue RequestError => e
353
+ elog(e.to_s)
354
+ end
355
+
356
+ service = client.pfservice
357
+
358
+ # If we have any open port forwards, we need to close them down
359
+ # otherwise we'll end up with local listeners which aren't connected
360
+ # to valid channels in the migrated meterpreter instance.
361
+ existing_relays = []
362
+
363
+ if service
364
+ service.each_tcp_relay do |lhost, lport, rhost, rport, opts|
365
+ next unless opts['MeterpreterRelay']
366
+ if existing_relays.empty?
367
+ print_status("Removing existing TCP relays...")
368
+ end
369
+ if (service.stop_tcp_relay(lport, lhost))
370
+ print_status("Successfully stopped TCP relay on #{lhost || '0.0.0.0'}:#{lport}")
371
+ existing_relays << {
372
+ :lport => lport,
373
+ :opts => opts
374
+ }
375
+ else
376
+ print_error("Failed to stop TCP relay on #{lhost || '0.0.0.0'}:#{lport}")
377
+ next
378
+ end
379
+ end
380
+ unless existing_relays.empty?
381
+ print_status("#{existing_relays.length} TCP relay(s) removed.")
382
+ end
383
+ end
384
+
385
+ server ? print_status("Migrating from #{server.pid} to #{pid}...") : print_status("Migrating to #{pid}")
386
+
387
+ # Do this thang.
388
+ client.core.migrate(pid)
389
+
390
+ print_status("Migration completed successfully.")
391
+
392
+ unless existing_relays.empty?
393
+ print_status("Recreating TCP relay(s)...")
394
+ existing_relays.each do |r|
395
+ client.pfservice.start_tcp_relay(r[:lport], r[:opts])
396
+ print_status("Local TCP relay recreated: #{r[:opts]['LocalHost'] || '0.0.0.0'}:#{r[:lport]} <-> #{r[:opts]['PeerHost']}:#{r[:opts]['PeerPort']}")
397
+ end
398
+ end
399
+
400
+ end
401
+
402
+ def cmd_load_help
403
+ print_line("Usage: load ext1 ext2 ext3 ...")
404
+ print_line
405
+ print_line "Loads a meterpreter extension module or modules."
406
+ print_line @@load_opts.usage
407
+ end
408
+
409
+ #
410
+ # Loads one or more meterpreter extensions.
411
+ #
412
+ def cmd_load(*args)
413
+ if (args.length == 0)
414
+ args.unshift("-h")
415
+ end
416
+
417
+ @@load_opts.parse(args) { |opt, idx, val|
418
+ case opt
419
+ when "-l"
420
+ exts = SortedSet.new
421
+ msf_path = MeterpreterBinaries.metasploit_data_dir
422
+ gem_path = MeterpreterBinaries.local_dir
423
+ [msf_path, gem_path].each do |path|
424
+ ::Dir.entries(path).each { |f|
425
+ if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
426
+ exts.add($1)
427
+ end
428
+ }
429
+ end
430
+ print(exts.to_a.join("\n") + "\n")
431
+
432
+ return true
433
+ when "-h"
434
+ cmd_load_help
435
+ return true
436
+ end
437
+ }
438
+
439
+ # Load each of the modules
440
+ args.each { |m|
441
+ md = m.downcase
442
+
443
+ if (extensions.include?(md))
444
+ print_error("The '#{md}' extension has already been loaded.")
445
+ next
446
+ end
447
+
448
+ print("Loading extension #{md}...")
449
+
450
+ begin
451
+ # Use the remote side, then load the client-side
452
+ if (client.core.use(md) == true)
453
+ add_extension_client(md)
454
+ end
455
+ rescue
456
+ print_line
457
+ log_error("Failed to load extension: #{$!}")
458
+ next
459
+ end
460
+
461
+ print_line("success.")
462
+ }
463
+
464
+ return true
465
+ end
466
+
467
+ def cmd_load_tabs(str, words)
468
+ tabs = SortedSet.new
469
+ msf_path = MeterpreterBinaries.metasploit_data_dir
470
+ gem_path = MeterpreterBinaries.local_dir
471
+ [msf_path, gem_path].each do |path|
472
+ ::Dir.entries(path).each { |f|
473
+ if (::File.file?(::File.join(path, f)) && f =~ /ext_server_(.*)\.#{client.binary_suffix}/ )
474
+ if (not extensions.include?($1))
475
+ tabs.add($1)
476
+ end
477
+ end
478
+ }
479
+ end
480
+ return tabs.to_a
481
+ end
482
+
483
+ def cmd_use(*args)
484
+ #print_error("Warning: The 'use' command is deprecated in favor of 'load'")
485
+ cmd_load(*args)
486
+ end
487
+ alias cmd_use_help cmd_load_help
488
+ alias cmd_use_tabs cmd_load_tabs
489
+
490
+ def cmd_read_help
491
+ print_line "Usage: read <channel_id> [length]"
492
+ print_line
493
+ print_line "Reads data from the supplied channel."
494
+ print_line
495
+ end
496
+
497
+ #
498
+ # Reads data from a channel.
499
+ #
500
+ def cmd_read(*args)
501
+ if (args.length == 0)
502
+ cmd_read_help
503
+ return true
504
+ end
505
+
506
+ cid = args[0].to_i
507
+ length = (args.length >= 2) ? args[1].to_i : 16384
508
+ channel = client.find_channel(cid)
509
+
510
+ if (!channel)
511
+ print_error("Channel #{cid} is not valid.")
512
+ return true
513
+ end
514
+
515
+ data = channel.read(length)
516
+
517
+ if (data and data.length)
518
+ print("Read #{data.length} bytes from #{cid}:\n\n#{data}\n")
519
+ else
520
+ print_error("No data was returned.")
521
+ end
522
+
523
+ return true
524
+ end
525
+
526
+ alias cmd_read_tabs cmd_close_tabs
527
+
528
+ def cmd_run_help
529
+ print_line "Usage: run <script> [arguments]"
530
+ print_line
531
+ print_line "Executes a ruby script or Metasploit Post module in the context of the"
532
+ print_line "meterpreter session. Post modules can take arguments in var=val format."
533
+ print_line "Example: run post/foo/bar BAZ=abcd"
534
+ print_line
535
+ end
536
+
537
+ #
538
+ # Executes a script in the context of the meterpreter session.
539
+ #
540
+ def cmd_run(*args)
541
+ if args.length == 0
542
+ cmd_run_help
543
+ return true
544
+ end
545
+
546
+ # Get the script name
547
+ begin
548
+ script_name = args.shift
549
+ # First try it as a Post module if we have access to the Metasploit
550
+ # Framework instance. If we don't, or if no such module exists,
551
+ # fall back to using the scripting interface.
552
+ if (msf_loaded? and mod = client.framework.modules.create(script_name))
553
+ original_mod = mod
554
+ reloaded_mod = client.framework.modules.reload_module(original_mod)
555
+
556
+ unless reloaded_mod
557
+ error = client.framework.modules.module_load_error_by_path[original_mod.file_path]
558
+ print_error("Failed to reload module: #{error}")
559
+
560
+ return
561
+ end
562
+
563
+ opts = (args + [ "SESSION=#{client.sid}" ]).join(',')
564
+ reloaded_mod.run_simple(
565
+ #'RunAsJob' => true,
566
+ 'LocalInput' => shell.input,
567
+ 'LocalOutput' => shell.output,
568
+ 'OptionStr' => opts
569
+ )
570
+ else
571
+ # the rest of the arguments get passed in through the binding
572
+ client.execute_script(script_name, args)
573
+ end
574
+ rescue
575
+ print_error("Error in script: #{$!.class} #{$!}")
576
+ elog("Error in script: #{$!.class} #{$!}")
577
+ dlog("Callstack: #{$@.join("\n")}")
578
+ end
579
+ end
580
+
581
+ def cmd_run_tabs(str, words)
582
+ tabs = []
583
+ if(not words[1] or not words[1].match(/^\//))
584
+ begin
585
+ if (msf_loaded?)
586
+ tabs += tab_complete_postmods
587
+ end
588
+ [
589
+ ::Msf::Sessions::Meterpreter.script_base,
590
+ ::Msf::Sessions::Meterpreter.user_script_base
591
+ ].each do |dir|
592
+ next if not ::File.exist? dir
593
+ tabs += ::Dir.new(dir).find_all { |e|
594
+ path = dir + ::File::SEPARATOR + e
595
+ ::File.file?(path) and ::File.readable?(path)
596
+ }
597
+ end
598
+ rescue Exception
599
+ end
600
+ end
601
+ return tabs.map { |e| e.sub(/\.rb$/, '') }
602
+ end
603
+
604
+
605
+ #
606
+ # Executes a script in the context of the meterpreter session in the background
607
+ #
608
+ def cmd_bgrun(*args)
609
+ if args.length == 0
610
+ print_line(
611
+ "Usage: bgrun <script> [arguments]\n\n" +
612
+ "Executes a ruby script in the context of the meterpreter session.")
613
+ return true
614
+ end
615
+
616
+ jid = self.bgjob_id
617
+ self.bgjob_id += 1
618
+
619
+ # Get the script name
620
+ self.bgjobs[jid] = Rex::ThreadFactory.spawn("MeterpreterBGRun(#{args[0]})-#{jid}", false, jid, args) do |myjid,xargs|
621
+ ::Thread.current[:args] = xargs.dup
622
+ begin
623
+ # the rest of the arguments get passed in through the binding
624
+ client.execute_script(args.shift, args)
625
+ rescue ::Exception
626
+ print_error("Error in script: #{$!.class} #{$!}")
627
+ elog("Error in script: #{$!.class} #{$!}")
628
+ dlog("Callstack: #{$@.join("\n")}")
629
+ end
630
+ self.bgjobs[myjid] = nil
631
+ print_status("Background script with Job ID #{myjid} has completed (#{::Thread.current[:args].inspect})")
632
+ end
633
+
634
+ print_status("Executed Meterpreter with Job ID #{jid}")
635
+ end
636
+
637
+ #
638
+ # Map this to the normal run command tab completion
639
+ #
640
+ def cmd_bgrun_tabs(*args)
641
+ cmd_run_tabs(*args)
642
+ end
643
+
644
+ #
645
+ # Kill a background job
646
+ #
647
+ def cmd_bgkill(*args)
648
+ if args.length == 0
649
+ print_line("Usage: bgkill [id]")
650
+ return
651
+ end
652
+
653
+ args.each do |jid|
654
+ jid = jid.to_i
655
+ if self.bgjobs[jid]
656
+ print_status("Killing background job #{jid}...")
657
+ self.bgjobs[jid].kill
658
+ self.bgjobs[jid] = nil
659
+ else
660
+ print_error("Job #{jid} was not running")
661
+ end
662
+ end
663
+ end
664
+
665
+ #
666
+ # List background jobs
667
+ #
668
+ def cmd_bglist(*args)
669
+ self.bgjobs.each_index do |jid|
670
+ if self.bgjobs[jid]
671
+ print_status("Job #{jid}: #{self.bgjobs[jid][:args].inspect}")
672
+ end
673
+ end
674
+ end
675
+
676
+ def cmd_info_help
677
+ print_line 'Usage: info <module>'
678
+ print_line
679
+ print_line 'Prints information about a post-exploitation module'
680
+ print_line
681
+ end
682
+
683
+ #
684
+ # Show info for a given Post module.
685
+ #
686
+ # See also +cmd_info+ in lib/msf/ui/console/command_dispatcher/core.rb
687
+ #
688
+ def cmd_info(*args)
689
+ return unless msf_loaded?
690
+
691
+ if args.length != 1 or args.include?("-h")
692
+ cmd_info_help
693
+ return
694
+ end
695
+
696
+ module_name = args.shift
697
+ mod = client.framework.modules.create(module_name);
698
+
699
+ if mod.nil?
700
+ print_error 'Invalid module: ' << module_name
701
+ end
702
+
703
+ if (mod)
704
+ print_line(::Msf::Serializer::ReadableText.dump_module(mod))
705
+ mod_opt = ::Msf::Serializer::ReadableText.dump_options(mod, ' ')
706
+ print_line("\nModule options (#{mod.fullname}):\n\n#{mod_opt}") if (mod_opt and mod_opt.length > 0)
707
+ end
708
+ end
709
+
710
+ def cmd_info_tabs(*args)
711
+ return unless msf_loaded?
712
+ tab_complete_postmods
713
+ end
714
+
715
+ #
716
+ # Writes data to a channel.
717
+ #
718
+ @@write_opts = Rex::Parser::Arguments.new(
719
+ "-f" => [ true, "Write the contents of a file on disk" ],
720
+ "-h" => [ false, "Help menu." ])
721
+
722
+ def cmd_write_help
723
+ print_line "Usage: write [options] channel_id"
724
+ print_line
725
+ print_line "Writes data to the supplied channel."
726
+ print_line @@write_opts.usage
727
+ end
728
+
729
+ def cmd_write(*args)
730
+ if (args.length == 0 or args.include?("-h"))
731
+ cmd_write_help
732
+ return
733
+ end
734
+
735
+ src_file = nil
736
+ cid = nil
737
+
738
+ @@write_opts.parse(args) { |opt, idx, val|
739
+ case opt
740
+ when "-f"
741
+ src_file = val
742
+ else
743
+ cid = val.to_i
744
+ end
745
+ }
746
+
747
+ # Find the channel associated with this cid, assuming the cid is valid.
748
+ if ((!cid) or (!(channel = client.find_channel(cid))))
749
+ print_error("Invalid channel identifier specified.")
750
+ return true
751
+ end
752
+
753
+ # If they supplied a source file, read in its contents and write it to
754
+ # the channel
755
+ if (src_file)
756
+ begin
757
+ data = ''
758
+
759
+ ::File.open(src_file, 'rb') { |f|
760
+ data = f.read(f.stat.size)
761
+ }
762
+
763
+ rescue Errno::ENOENT
764
+ print_error("Invalid source file specified: #{src_file}")
765
+ return true
766
+ end
767
+
768
+ if (data and data.length > 0)
769
+ channel.write(data)
770
+ print_status("Wrote #{data.length} bytes to channel #{cid}.")
771
+ else
772
+ print_error("No data to send from file #{src_file}")
773
+ return true
774
+ end
775
+ # Otherwise, read from the input descriptor until we're good to go.
776
+ else
777
+ print("Enter data followed by a '.' on an empty line:\n\n")
778
+
779
+ data = ''
780
+
781
+ # Keep truckin'
782
+ while (s = shell.input.gets)
783
+ break if (s =~ /^\.\r?\n?$/)
784
+ data += s
785
+ end
786
+
787
+ if (!data or data.length == 0)
788
+ print_error("No data to send.")
789
+ else
790
+ channel.write(data)
791
+ print_status("Wrote #{data.length} bytes to channel #{cid}.")
792
+ end
793
+ end
794
+
795
+ return true
796
+ end
797
+
798
+ def cmd_resource_help
799
+ print_line "Usage: resource <path1> [path2 ...]"
800
+ print_line
801
+ print_line "Run the commands stored in the supplied files."
802
+ print_line
803
+ end
804
+
805
+ def cmd_resource(*args)
806
+ if args.empty?
807
+ return false
808
+ end
809
+ args.each do |glob|
810
+ files = ::Dir.glob(::File.expand_path(glob))
811
+ if files.empty?
812
+ print_error("No such file #{glob}")
813
+ next
814
+ end
815
+ files.each do |filename|
816
+ print_status("Reading #{filename}")
817
+ if (not ::File.readable?(filename))
818
+ print_error("Could not read file #{filename}")
819
+ next
820
+ else
821
+ ::File.open(filename, "r").each_line do |line|
822
+ next if line.strip.length < 1
823
+ next if line[0,1] == "#"
824
+ begin
825
+ print_status("Running #{line}")
826
+ client.console.run_single(line)
827
+ rescue ::Exception => e
828
+ print_error("Error Running Command #{line}: #{e.class} #{e}")
829
+ end
830
+
831
+ end
832
+ end
833
+ end
834
+ end
835
+ end
836
+
837
+ def cmd_resource_tabs(str, words)
838
+ return [] if words.length > 1
839
+
840
+ tab_complete_filenames(str, words)
841
+ end
842
+
843
+ def cmd_enable_unicode_encoding
844
+ client.encode_unicode = true
845
+ print_status("Unicode encoding is enabled")
846
+ end
847
+
848
+ def cmd_disable_unicode_encoding
849
+ client.encode_unicode = false
850
+ print_status("Unicode encoding is disabled")
851
+ end
852
+
853
+ @@client_extension_search_paths = [ ::File.join(Rex::Root, "post", "meterpreter", "ui", "console", "command_dispatcher") ]
854
+
855
+ def self.add_client_extension_search_path(path)
856
+ @@client_extension_search_paths << path unless @@client_extension_search_paths.include?(path)
857
+ end
858
+ def self.client_extension_search_paths
859
+ @@client_extension_search_paths
860
+ end
804
861
 
805
862
  protected
806
863
 
807
- attr_accessor :extensions # :nodoc:
808
- attr_accessor :bgjobs, :bgjob_id # :nodoc:
809
-
810
- CommDispatcher = Console::CommandDispatcher
811
-
812
- #
813
- # Loads the client extension specified in mod
814
- #
815
- def add_extension_client(mod)
816
- loaded = false
817
- klass = nil
818
- self.class.client_extension_search_paths.each do |path|
819
- path = ::File.join(path, "#{mod}.rb")
820
- klass = CommDispatcher.check_hash(path)
821
- if (klass == nil)
822
- old = CommDispatcher.constants
823
- next unless ::File.exist? path
824
-
825
- if (require(path))
826
- new = CommDispatcher.constants
827
- diff = new - old
828
-
829
- next if (diff.empty?)
830
-
831
- klass = CommDispatcher.const_get(diff[0])
832
-
833
- CommDispatcher.set_hash(path, klass)
834
- loaded = true
835
- break
836
- else
837
- print_error("Failed to load client script file: #{path}")
838
- return false
839
- end
840
- else
841
- # the klass is already loaded, from a previous invocation
842
- loaded = true
843
- break
844
- end
845
- end
846
- unless loaded
847
- print_error("Failed to load client portion of #{mod}.")
848
- return false
849
- end
850
-
851
- # Enstack the dispatcher
852
- self.shell.enstack_dispatcher(klass)
853
-
854
- # Insert the module into the list of extensions
855
- self.extensions << mod
856
- end
857
-
858
- def tab_complete_postmods
859
- tabs = client.framework.modules.post.map { |name,klass|
860
- mod = klass.new
861
- if mod.session_compatible?(client)
862
- mod.fullname.dup
863
- else
864
- nil
865
- end
866
- }
867
-
868
- # nils confuse readline
869
- tabs.compact
870
- end
871
-
872
- def tab_complete_channels
873
- client.channels.keys.map { |k| k.to_s }
874
- end
864
+ attr_accessor :extensions # :nodoc:
865
+ attr_accessor :bgjobs, :bgjob_id # :nodoc:
866
+
867
+ CommDispatcher = Console::CommandDispatcher
868
+
869
+ #
870
+ # Loads the client extension specified in mod
871
+ #
872
+ def add_extension_client(mod)
873
+ loaded = false
874
+ klass = nil
875
+ self.class.client_extension_search_paths.each do |path|
876
+ path = ::File.join(path, "#{mod}.rb")
877
+ klass = CommDispatcher.check_hash(path)
878
+ if (klass == nil)
879
+ old = CommDispatcher.constants
880
+ next unless ::File.exist? path
881
+
882
+ if (require(path))
883
+ new = CommDispatcher.constants
884
+ diff = new - old
885
+
886
+ next if (diff.empty?)
887
+
888
+ klass = CommDispatcher.const_get(diff[0])
889
+
890
+ CommDispatcher.set_hash(path, klass)
891
+ loaded = true
892
+ break
893
+ else
894
+ print_error("Failed to load client script file: #{path}")
895
+ return false
896
+ end
897
+ else
898
+ # the klass is already loaded, from a previous invocation
899
+ loaded = true
900
+ break
901
+ end
902
+ end
903
+ unless loaded
904
+ print_error("Failed to load client portion of #{mod}.")
905
+ return false
906
+ end
907
+
908
+ # Enstack the dispatcher
909
+ self.shell.enstack_dispatcher(klass)
910
+
911
+ # Insert the module into the list of extensions
912
+ self.extensions << mod
913
+ end
914
+
915
+ def tab_complete_postmods
916
+ tabs = client.framework.modules.post.map { |name,klass|
917
+ mod = client.framework.modules.post.create(name)
918
+ if mod and mod.session_compatible?(client)
919
+ mod.fullname.dup
920
+ else
921
+ nil
922
+ end
923
+ }
924
+
925
+ # nils confuse readline
926
+ tabs.compact
927
+ end
928
+
929
+ def tab_complete_channels
930
+ client.channels.keys.map { |k| k.to_s }
931
+ end
875
932
 
876
933
  end
877
934