Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

msfvenom 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. #!/usr/bin/env ruby
  2. # -*- coding: binary -*-
  3. class MsfVenomError < StandardError; end
  4. class HelpError < StandardError; end
  5. class UsageError < MsfVenomError; end
  6. require 'optparse'
  7. require 'timeout'
  8. def require_deps
  9. msfbase = __FILE__
  10. while File.symlink?(msfbase)
  11. msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase))
  12. end
  13. $:.unshift(File.expand_path(File.join(File.dirname(msfbase), 'lib')))
  14. require 'msfenv'
  15. $:.unshift(ENV['MSF_LOCAL_LIB']) if ENV['MSF_LOCAL_LIB']
  16. require 'rex'
  17. require 'msf/ui'
  18. require 'msf/base'
  19. require 'msf/core/payload_generator'
  20. @framework_loaded = true
  21. end
  22. # Creates a new framework object.
  23. #
  24. # @note Ignores any previously cached value.
  25. # @param (see ::Msf::Simple::Framework.create)
  26. # @return [Msf::Framework]
  27. def init_framework(create_opts={})
  28. require_deps unless @framework_loaded
  29. create_opts[:module_types] ||= [
  30. ::Msf::MODULE_PAYLOAD, ::Msf::MODULE_ENCODER, ::Msf::MODULE_NOP
  31. ]
  32. create_opts[:module_types].map! do |type|
  33. type = Msf.const_get("MODULE_#{type.upcase}")
  34. end
  35. @framework = ::Msf::Simple::Framework.create
  36. end
  37. # Cached framework object
  38. #
  39. # @return [Msf::Framework]
  40. def framework
  41. return @framework if @framework
  42. init_framework
  43. @framework
  44. end
  45. def parse_args(args)
  46. opts = {}
  47. datastore = {}
  48. opt = OptionParser.new
  49. banner = "MsfVenom - a Metasploit standalone payload generator.\n"
  50. banner << "Also a replacement for msfpayload and msfencode.\n"
  51. banner << "Usage: #{$0} [options] <var=val>\n"
  52. banner << "Example: #{$0} -p windows/meterpreter/reverse_tcp LHOST=<IP> -f exe -o payload.exe"
  53. opt.banner = banner
  54. opt.separator('')
  55. opt.separator('Options:')
  56. opt.on('-l', '--list <type>', Array, 'List all modules for [type]. Types are: payloads, encoders, nops, platforms, archs, encrypt, formats, all') do |l|
  57. if l.to_s.empty?
  58. l = ["all"]
  59. end
  60. opts[:list] = l
  61. end
  62. opt.on('-p', '--payload <payload>', String,
  63. "Payload to use (--list payloads to list, --list-options for arguments). Specify '-' or STDIN for custom") do |p|
  64. if p == '-'
  65. opts[:payload] = 'stdin'
  66. else
  67. opts[:payload] = p
  68. end
  69. end
  70. opt.on('--list-options', "List --payload <value>'s standard, advanced and evasion options") do
  71. opts[:list_options] = true
  72. end
  73. opt.on('-f', '--format <format>', String, "Output format (use --list formats to list)") do |f|
  74. opts[:format] = f.downcase
  75. end
  76. opt.on('-e', '--encoder <encoder>', String, 'The encoder to use (use --list encoders to list)') do |e|
  77. opts[:encoder] = e
  78. end
  79. opt.on('--sec-name <value>', String, 'The new section name to use when generating large Windows binaries. Default: random 4-character alpha string') do |s|
  80. opts[:secname] = s
  81. end
  82. opt.on('--smallest', 'Generate the smallest possible payload using all available encoders') do
  83. opts[:smallest] = true
  84. end
  85. opt.on('--encrypt <value>', String, 'The type of encryption or encoding to apply to the shellcode (use --list encrypt to list)') do |e|
  86. opts[:encryption_format] = e
  87. end
  88. opt.on('--encrypt-key <value>', String, 'A key to be used for --encrypt') do |e|
  89. init_framework
  90. opts[:encryption_key] = Rex::Text.dehex(e)
  91. end
  92. opt.on('--encrypt-iv <value>', String, 'An initialization vector for --encrypt') do |e|
  93. opts[:encryption_iv] = e
  94. end
  95. opt.on('-a', '--arch <arch>', String, 'The architecture to use for --payload and --encoders (use --list archs to list)') do |a|
  96. opts[:arch] = a
  97. end
  98. opt.on('--platform <platform>', String, 'The platform for --payload (use --list platforms to list)') do |l|
  99. opts[:platform] = l
  100. end
  101. opt.on('-o', '--out <path>', 'Save the payload to a file') do |x|
  102. opts[:out] = x
  103. end
  104. opt.on('-b', '--bad-chars <list>', String, 'Characters to avoid example: \'\x00\xff\'') do |b|
  105. init_framework
  106. opts[:badchars] = Rex::Text.dehex(b)
  107. end
  108. opt.on('-n', '--nopsled <length>', Integer, 'Prepend a nopsled of [length] size on to the payload') do |n|
  109. opts[:nops] = n.to_i
  110. end
  111. opt.on('--pad-nops', 'Use nopsled size specified by -n <length> as the total payload size, auto-prepending a nopsled of quantity (nops minus payload length)') do
  112. opts[:padnops] = true
  113. end
  114. opt.on('-s', '--space <length>', Integer, 'The maximum size of the resulting payload') do |s|
  115. opts[:space] = s
  116. end
  117. opt.on('--encoder-space <length>', Integer, 'The maximum size of the encoded payload (defaults to the -s value)') do |s|
  118. opts[:encoder_space] = s
  119. end
  120. opt.on('-i', '--iterations <count>', Integer, 'The number of times to encode the payload') do |i|
  121. opts[:iterations] = i
  122. end
  123. opt.on('-c', '--add-code <path>', String, 'Specify an additional win32 shellcode file to include') do |x|
  124. opts[:add_code] = x
  125. end
  126. opt.on('-x', '--template <path>', String, 'Specify a custom executable file to use as a template') do |x|
  127. opts[:template] = x
  128. end
  129. opt.on('-k', '--keep', 'Preserve the --template behaviour and inject the payload as a new thread') do
  130. opts[:keep] = true
  131. end
  132. opt.on('-v', '--var-name <value>', String, 'Specify a custom variable name to use for certain output formats') do |x|
  133. opts[:var_name] = x
  134. end
  135. opt.on('-t', '--timeout <second>', Integer, "The number of seconds to wait when reading the payload from STDIN (default 30, 0 to disable)") do |x|
  136. opts[:timeout] = x
  137. end
  138. opt.on_tail('-h', '--help', 'Show this message') do
  139. raise HelpError, "#{opt}"
  140. end
  141. begin
  142. opt.parse!(args)
  143. rescue OptionParser::InvalidOption => e
  144. raise UsageError, "Invalid option\n#{opt}"
  145. rescue OptionParser::MissingArgument => e
  146. raise UsageError, "Missing required argument for option\n#{opt}"
  147. end
  148. if opts.empty?
  149. raise UsageError, "No options\n#{opt}"
  150. end
  151. if args
  152. args.each do |x|
  153. k,v = x.split('=', 2)
  154. datastore[k.upcase] = v.to_s
  155. end
  156. if opts[:payload].to_s =~ /[\_\/]reverse/ && datastore['LHOST'].nil?
  157. init_framework
  158. datastore['LHOST'] = Rex::Socket.source_address
  159. end
  160. end
  161. if opts[:payload].nil? # if no payload option is selected assume we are reading it from stdin
  162. opts[:payload] = "stdin"
  163. end
  164. if opts[:payload].downcase == 'stdin' && !opts[:list]
  165. $stderr.puts "Attempting to read payload from STDIN..."
  166. begin
  167. opts[:timeout] ||= 30
  168. ::Timeout.timeout(opts[:timeout]) do
  169. opts[:stdin] = payload_stdin
  170. end
  171. rescue Timeout::Error
  172. opts[:stdin] = ''
  173. end
  174. end
  175. opts[:datastore] = datastore
  176. opts
  177. end
  178. # Read a raw payload from stdin (or whatever IO object we're currently
  179. # using as stdin, see {#initialize})
  180. #
  181. # @return [String]
  182. def payload_stdin
  183. @in = $stdin
  184. @in.binmode
  185. payload = @in.read
  186. payload
  187. end
  188. def dump_platforms
  189. init_framework(:module_types => [])
  190. supported_platforms = []
  191. Msf::Module::Platform.subclasses.each {|c| supported_platforms << c.realname.downcase}
  192. tbl = Rex::Text::Table.new(
  193. 'Indent' => 4,
  194. 'Header' => "Framework Platforms [--platform <value>]",
  195. 'Columns' =>
  196. [
  197. "Name",
  198. ])
  199. supported_platforms.sort.each do |name|
  200. tbl << [name]
  201. end
  202. "\n" + tbl.to_s + "\n"
  203. end
  204. def dump_archs
  205. init_framework(:module_types => [])
  206. supported_archs = ARCH_ALL.dup
  207. tbl = Rex::Text::Table.new(
  208. 'Indent' => 4,
  209. 'Header' => "Framework Architectures [--arch <value>]",
  210. 'Columns' =>
  211. [
  212. "Name",
  213. ])
  214. supported_archs.sort.each do |name|
  215. tbl << [name]
  216. end
  217. "\n" + tbl.to_s + "\n"
  218. end
  219. def dump_encrypt
  220. init_framework(:module_types => [])
  221. tbl = Rex::Text::Table.new(
  222. 'Indent' => 4,
  223. 'Header' => "Framework Encryption Formats [--encrypt <value>]",
  224. 'Columns' =>
  225. [
  226. "Name",
  227. ])
  228. ::Msf::Simple::Buffer.encryption_formats.each do |name|
  229. tbl << [ name]
  230. end
  231. "\n" + tbl.to_s + "\n"
  232. end
  233. def dump_formats
  234. init_framework(:module_types => [])
  235. tbl1 = Rex::Text::Table.new(
  236. 'Indent' => 4,
  237. 'Header' => "Framework Executable Formats [--format <value>]",
  238. 'Columns' =>
  239. [
  240. "Name"
  241. ])
  242. ::Msf::Util::EXE.to_executable_fmt_formats.each do |name|
  243. tbl1 << [ name ]
  244. end
  245. tbl2 = Rex::Text::Table.new(
  246. 'Indent' => 4,
  247. 'Header' => "Framework Transform Formats [--format <value>]",
  248. 'Columns' =>
  249. [
  250. "Name"
  251. ])
  252. ::Msf::Simple::Buffer.transform_formats.each do |name|
  253. tbl2 << [ name ]
  254. end
  255. "\n" + tbl1.to_s + "\n" + tbl2.to_s + "\n"
  256. end
  257. def dump_payloads
  258. init_framework(:module_types => [ :payload ])
  259. tbl = Rex::Text::Table.new(
  260. 'Indent' => 4,
  261. 'Header' => "Framework Payloads (#{framework.stats.num_payloads} total) [--payload <value>]",
  262. 'Columns' =>
  263. [
  264. "Name",
  265. "Description"
  266. ])
  267. framework.payloads.each_module { |name, mod|
  268. tbl << [ name, mod.new.description.split.join(' ') ]
  269. }
  270. "\n" + tbl.to_s + "\n"
  271. end
  272. def dump_encoders(arch = nil)
  273. init_framework(:module_types => [ :encoder ])
  274. tbl = Rex::Text::Table.new(
  275. 'Indent' => 4,
  276. 'Header' => "Framework Encoders" + ((arch) ? " (architectures: #{arch})" : "") + " [--encoder <value>]",
  277. 'Columns' =>
  278. [
  279. "Name",
  280. "Rank",
  281. "Description"
  282. ])
  283. cnt = 0
  284. framework.encoders.each_module(
  285. 'Arch' => arch ? arch.split(',') : nil) { |name, mod|
  286. tbl << [ name, mod.rank_to_s, mod.new.name ]
  287. cnt += 1
  288. }
  289. (cnt > 0) ? "\n" + tbl.to_s + "\n" : "\nNo compatible encoders found.\n\n"
  290. end
  291. def dump_nops
  292. init_framework(:module_types => [ :nop ])
  293. tbl = Rex::Text::Table.new(
  294. 'Indent' => 4,
  295. 'Header' => "Framework NOPs (#{framework.stats.num_nops} total)",
  296. 'Columns' =>
  297. [
  298. "Name",
  299. "Description"
  300. ])
  301. framework.nops.each_module { |name, mod|
  302. tbl << [ name, mod.new.description.split.join(' ') ]
  303. }
  304. "\n" + tbl.to_s + "\n"
  305. end
  306. begin
  307. generator_opts = parse_args(ARGV)
  308. rescue HelpError => e
  309. $stderr.puts e.message
  310. exit(1)
  311. rescue MsfVenomError => e
  312. $stderr.puts "Error: #{e.message}"
  313. exit(1)
  314. end
  315. if generator_opts[:list]
  316. generator_opts[:list].each do |mod|
  317. case mod.downcase
  318. when "payloads", "payload", "p"
  319. $stdout.puts dump_payloads
  320. when "encoders", "encoder", "e"
  321. $stdout.puts dump_encoders(generator_opts[:arch])
  322. when "nops", "nop", "n"
  323. $stdout.puts dump_nops
  324. when "platforms", "dump_platform"
  325. $stdout.puts dump_platforms
  326. when "archs", "dump_arch"
  327. $stdout.puts dump_archs
  328. when "encrypts", "encrypt", "encryption"
  329. $stdout.puts dump_encrypt
  330. when "formats", "format", "f"
  331. $stdout.puts dump_formats
  332. when "all", "a"
  333. # Init here so #dump_payloads doesn't create a framework with
  334. # only payloads, etc.
  335. init_framework
  336. $stdout.puts dump_payloads
  337. $stdout.puts dump_encoders
  338. $stdout.puts dump_nops
  339. $stdout.puts dump_platforms
  340. $stdout.puts dump_archs
  341. $stdout.puts dump_encrypt
  342. $stdout.puts dump_formats
  343. else
  344. $stderr.puts "Invalid type (#{mod}). These are valid: payloads, encoders, nops, platforms, archs, encrypt, formats, all"
  345. end
  346. end
  347. exit(0)
  348. end
  349. if generator_opts[:list_options]
  350. payload_mod = framework.payloads.create(generator_opts[:payload])
  351. if payload_mod.nil?
  352. $stderr.puts "Invalid payload: #{generator_opts[:payload]}"
  353. exit(1)
  354. end
  355. $stderr.puts "Options for #{payload_mod.fullname}:\n" + "="*25 + "\n\n"
  356. $stdout.puts ::Msf::Serializer::ReadableText.dump_module(payload_mod, ' ')
  357. $stderr.puts "\nAdvanced options for #{payload_mod.fullname}:\n" + "="*25 + "\n\n"
  358. $stdout.puts ::Msf::Serializer::ReadableText.dump_advanced_options(payload_mod, ' ')
  359. $stderr.puts "\nEvasion options for #{payload_mod.fullname}:\n" + "="*25 + "\n\n"
  360. $stdout.puts ::Msf::Serializer::ReadableText.dump_evasion_options(payload_mod, ' ')
  361. exit(0)
  362. end
  363. generator_opts[:framework] = framework
  364. generator_opts[:cli] = true
  365. begin
  366. venom_generator = Msf::PayloadGenerator.new(generator_opts)
  367. payload = venom_generator.generate_payload
  368. rescue Msf::InvalidFormat => e
  369. $stderr.puts "Error: #{e.message}"
  370. $stderr.puts dump_formats
  371. rescue ::Exception => e
  372. elog("#{e.class} : #{e.message}\n#{e.backtrace * "\n"}")
  373. $stderr.puts "Error: #{e.message}"
  374. end
  375. # No payload generated, no point to go on
  376. exit(2) unless payload
  377. if generator_opts[:out]
  378. begin
  379. ::File.open(generator_opts[:out], 'wb') do |f|
  380. f.write(payload)
  381. end
  382. $stderr.puts "Saved as: #{generator_opts[:out]}"
  383. rescue ::Exception => e
  384. # If I can't save it, then I can't save it. I don't think it matters what error.
  385. elog("#{e.class} : #{e.message}\n#{e.backtrace * "\n"}")
  386. $stderr.puts "Error: #{e.message}"
  387. end
  388. else
  389. output_stream = $stdout
  390. output_stream.binmode
  391. output_stream.write payload
  392. # trailing newline for pretty output
  393. $stderr.puts unless payload =~ /\n$/
  394. end