From 7b7413d85edf2a46a0ddb7c3fdcaab2ec19549b3 Mon Sep 17 00:00:00 2001 From: Tom Samstag Date: Fri, 11 Nov 2011 00:13:17 -0800 Subject: [PATCH] Bash format for msfencode/msfvenom This patch adds a Bash output format for msfencode and msfvenom. This is especially useful for local exploitation with shellcode in an environment variable. Example output: $ echo 'this is a test' | ./msfvenom -f bash [-] Using X86 architecture and Windows platform for stdin payload to change use -a and --platform export buf=\ $'\x74\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74'\ $'\x0a' It adds unit tests for the new format and also fixes a unit test that was broken (assert_equal 'AAAAAAAAA', Rex::Text.pattern_create(9,['A'])) due to a bug in the shortcut in pattern_create. --- lib/msf/base/simple/buffer.rb | 10 +++++++--- lib/rex/text.rb | 16 +++++++++++++++- lib/rex/text.rb.ut.rb | 2 ++ msfvenom | 4 ++-- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/lib/msf/base/simple/buffer.rb b/lib/msf/base/simple/buffer.rb index b250b09e1c..e1d887ca86 100644 --- a/lib/msf/base/simple/buffer.rb +++ b/lib/msf/base/simple/buffer.rb @@ -18,7 +18,7 @@ module Buffer # # Serializes a buffer to a provided format. The formats supported are raw, - # ruby, perl, c, js_be, js_le and java + # ruby, perl, bash, c, js_be, js_le and java # def self.transform(buf, fmt = "ruby") case fmt @@ -27,6 +27,8 @@ module Buffer buf = Rex::Text.to_ruby(buf) when 'perl', 'pl' buf = Rex::Text.to_perl(buf) + when 'bash', 'sh' + buf = Rex::Text.to_bash(buf) when 'c' buf = Rex::Text.to_c(buf) when 'js_be' @@ -44,7 +46,7 @@ module Buffer # # Creates a comment using the supplied format. The formats supported are - # raw, ruby, perl, js_be, js_le, c, and java. + # raw, ruby, perl, bash, js_be, js_le, c, and java. # def self.comment(buf, fmt = "ruby") case fmt @@ -53,6 +55,8 @@ module Buffer buf = Rex::Text.to_ruby_comment(buf) when 'perl', 'pl' buf = Rex::Text.to_perl_comment(buf) + when 'bash', 'sh' + buf = Rex::Text.to_bash_comment(buf) when 'c' buf = Rex::Text.to_c_comment(buf) when 'js_be', 'js_le' @@ -70,7 +74,7 @@ module Buffer # Returns the list of supported formats # def self.transform_formats - ['raw','ruby','rb','perl','pl','c','js_be','js_le','java'] + ['raw','ruby','rb','perl','pl','bash','sh','c','js_be','js_le','java'] end end diff --git a/lib/rex/text.rb b/lib/rex/text.rb index edfd85c33f..b3974f2cbd 100644 --- a/lib/rex/text.rb +++ b/lib/rex/text.rb @@ -94,6 +94,13 @@ module Text return hexify(str, wrap, '"', '" .', "my $#{name} = \n", '";') end + # + # Converts a raw string into a Bash buffer + # + def self.to_bash(str, wrap = DefaultWrap, name = "buf") + return hexify(str, wrap, '$\'', '\'\\', "export #{name}=\\\n", '\'') + end + # # Converts a raw string into a java byte array # @@ -124,6 +131,13 @@ module Text return wordwrap(str, 0, wrap, '', '# ') end + # + # Creates a Bash-style comment + # + def self.to_bash_comment(str, wrap = DefaultWrap) + return wordwrap(str, 0, wrap, '', '# ') + end + # # Returns the raw string # @@ -829,7 +843,7 @@ module Text # Return stupid uses return "" if length.to_i < 1 - return sets[0][0] * length if sets.size == 1 and sets[0].size == 1 + return sets[0][0].chr * length if sets.size == 1 and sets[0].size == 1 sets.length.times { offsets << 0 } diff --git a/lib/rex/text.rb.ut.rb b/lib/rex/text.rb.ut.rb index 0a6cc5d7a6..7c14bbb84f 100644 --- a/lib/rex/text.rb.ut.rb +++ b/lib/rex/text.rb.ut.rb @@ -158,6 +158,7 @@ class Rex::Text::UnitTest < Test::Unit::TestCase assert_equal("buf = \n\"\\x01\\x02\\xff\\x00\"\n", Rex::Text.to_ruby(str), 'to_ruby') assert_equal("my $buf = \n\"\\x01\\x02\\xff\\x00\";\n", Rex::Text.to_perl(str), 'to_perl') + assert_equal("export buf=\\\n$'\\x01\\x02\\xff\\x00\'\n", Rex::Text.to_bash(str), 'to_bash') assert_equal("unsigned char buf[] = \n\"\\x01\\x02\\xff\\x00\";\n", Rex::Text.to_c(str), 'to_c') # 0 -> 20 @@ -165,6 +166,7 @@ class Rex::Text::UnitTest < Test::Unit::TestCase assert_equal("buf = \n\"\\x00\\x01\\x02\\x03\" +\n\"\\x04\\x05\\x06\\x07\" +\n\"\\x08\\x09\\x0a\\x0b\" +\n\"\\x0c\\x0d\\x0e\\x0f\" +\n\"\\x10\\x11\\x12\\x13\"\n", Rex::Text.to_ruby(str, 20), 'to_ruby with wrap') assert_equal("my $buf = \n\"\\x00\\x01\\x02\\x03\" .\n\"\\x04\\x05\\x06\\x07\" .\n\"\\x08\\x09\\x0a\\x0b\" .\n\"\\x0c\\x0d\\x0e\\x0f\" .\n\"\\x10\\x11\\x12\\x13\";\n", Rex::Text.to_perl(str, 20), 'to_perl with wrap') + assert_equal("export buf=\\\n$'\\x00\\x01\\x02\\x03\'\\\n$'\\x04\\x05\\x06\\x07\'\\\n$'\\x08\\x09\\x0a\\x0b'\\\n$'\\x0c\\x0d\\x0e\\x0f'\\\n$'\\x10\\x11\\x12\\x13\'\n", Rex::Text.to_bash(str, 20), 'to_bash with wrap') assert_equal("unsigned char buf[] = \n\"\\x00\\x01\\x02\\x03\\x04\"\n\"\\x05\\x06\\x07\\x08\\x09\"\n\"\\x0a\\x0b\\x0c\\x0d\\x0e\"\n\"\\x0f\\x10\\x11\\x12\\x13\";\n", Rex::Text.to_c(str, 20, "buf"), 'to_c with wrap') assert_equal("\\x0a", Rex::Text.to_hex("\n"), 'to_hex newline') diff --git a/msfvenom b/msfvenom index c9136a60c0..23a6756081 100755 --- a/msfvenom +++ b/msfvenom @@ -379,12 +379,12 @@ if opts[:nopsled] end $stdout.binmode -if opts[:format] !~/ruby|rb|perl|pl|c|js|dll|elf/i +if opts[:format] !~/ruby|rb|perl|pl|bash|sh|c|js|dll|elf/i exe = Msf::Util::EXE.to_executable_fmt($framework, opts[:arch], opts[:platform], payload_raw, opts[:format], exeopts) end case opts[:format] -when /ruby|rb|perl|pl|c|js_le|raw/i +when /ruby|rb|perl|pl|bash|sh|c|js_le|raw/i $stdout.write Msf::Simple::Buffer.transform(payload_raw, opts[:format]) when /asp/ asp = Msf::Util::EXE.to_win32pe_asp($framework, payload_raw, exeopts)