Monday, May 11, 2009

Discovering Metasploit API : Utility functions

I often write scripts and programs to help me in my automation and testing projects. Many times I find it easier to do a one- or two- liner or write a short program than to search for a command line tool or GUI interface to accomplish my tasks. There are so many great specialized tools out there but I just don't do a good job of keeping track of their releases and functionality. However, I am very much fond of the scriptable frameworks because they give you best of the both worlds: flexibility and familiarity/repeatability.

So I have started playing with Metasploit API to better understand the framework and see what else I could be doing with it. I wanted to educate myself on the "framework" part. Besides, the quality of code is amazing - I am actually referencing Metasploit Framework for Ruby programming.

I started by reading the Developer's Guide and going through Rex API first.

Here are some things I will use going forward.

- Can discover Byte-order of the Host/target:

Rex::Arch.endian("ppc") => 1
Rex::Arch.endian("x86") => 0
- Can Pack and Re-pack data based on the byte-order
>> Rex::Arch.pack_addr(ARCH_X86,0x7889)
=> "\211x\000\000"
>> Rex::Arch.pack_addr(ARCH_MIPS,0x7889)
=> "\000\000x\211"


- Can programmatically take advantage of Inline assembly:
>> Rex::Assembly::Nasm.assemble("Mov ebp, 0x1")
=> "\275\001\000\000\000"


... and disassembly
>> Rex::Assembly::Nasm.disassemble("\275\001\000\000\000")
=> "00000000 BD01000000 mov ebp,0x1\n"


- Can determine OS cross-platform:
>> Rex::Compat.is_macosx
=> true


- Can open browser on target system ( also cross-platform. This example is what Windows likes)
Rex::Compat.open_browser(url='http://metasploit.com/')


Also, conversion and transformation facilities are very handy.
- Convert To ASCII encoding
>> Rex::Encoder::NDR::byte(0x5e)
=> "^"


- XOR encode/decode
Rex::Encoder::Xor::EncoderKlass = Rex::Encoding::Xor::Dword
enc=Rex::Encoder::Xor.new
enc.encode("AAA",'')


- or -
enc.encode("AAA",'BADCHARS-GO-HERE')
=> "\340\267y"


Now, this is nice and very useful - Obfuscating Javascript:
@opts={"Strings"=>nil, "Symbols"=>{"Namespaces"=>[], "Variables"=>['a'], "Classes"=>[], "Methods"=>['fun1']}}

js="var a=5; function fun1{ return false; }; //Comment"

Rex::Exploitation::ObfuscateJS.new(js, @opts).obfuscate
=> "vgMzBoAwuwunIaYjqXMaeHaGBWr gMzBoAwuwunIaYjqXMaeHaGBW=5;
function jibbyKShzFDQ{ return fgMzBoAwuwunIaYjqXMaeHaGBWlse; }; "


- Epoch to Human Time Conversion and back
>> Rex::ExtTime.sec_to_s(6444444)
=> "74 days 14 hours 7 mins 24 secs "


>> Rex::ExtTime.str_to_sec("5 days 4 hours 3 minutes")
=> 446580


- Equivalent of "which" on *nix platforms
>> Rex::FileUtils.find_full_path("apropos")
=> "/usr/bin/apropos"


- MIME encodings and attachments. I always miss this one - cannot seem to remember the format and have to go back to my old scripts to reference.

msg=Rex::MIME::Message.new
msg.add_part("hello",'text/plain',"8bit",nil)
msg.add_part_inline_attachment("this is inline", "inline_name")
msg.to_s
=> "\r\n\r\n--_Part_525_148040077_1316503564\r\nContent-Type: text/plain\r\nContent-Transfer-Encoding: 8bit\r\n\r\nhello\r\n--_Part_525_148040077_1316503564\r\nContent-Type: application/octet-stream; name=\"inline_name\"\r\nContent-Transfer-Encoding: base64\r\nContent-Disposition: inline; filename=\"inline_name\"\r\n\r\ndGhpcyBpcyBpbmxpbmU=\r\n\r\n--_Part_525_148040077_1316503564--\r\n"


- Ad-hoc Ruby block execution
Rex::Script.execute("puts 'hello'")


- Abundant Networking functionality
Rex::Socket.addr_atoi("1.2.3.4")
=> 16909060


Rex::Socket.addr_ntoa("\001\002\003\004")
=> "1.2.3.4"

>> Rex::Socket.bit2netmask(18)
=> "255.255.192.0"


...Invaluable:
>> Rex::Socket.cidr_crack("192.168.3.0/25")
=> ["192.168.3.0", "192.168.3.127"]


IP validation
>> Rex::Socket.dotted_ip?("1.2.3.4")
=> true
>> Rex::Socket.dotted_ip?("1.2.3.4.")
=> false


DNS Resolution
>> Rex::Socket.resolv_to_dotted("www.google.com")
=> "208.67.216.231"


sockaddr Structs
>> Rex::Socket.to_sockaddr("208.67.216.231","80")
=> "\020\002\000P\320C\330\347\000\000\000\000\000\000\000\000"

Again, Invaluable - Walking IP ranges
> rw=Rex::Socket::RangeWalker.new("192.168.1.1-192.168.2.2")
=> #
>> rw.next_ip
=> "192.168.1.1"
>> rw.next_ip
=> "192.168.1.2"
>> rw.next_ip
=> "192.168.1.3"

Subnet Walking
sw=Rex::Socket::SubnetWalker.new("192.168.1.0","20")
=> #
>> sw.netmask
=> "208.69.36.132"
>> sw.next_ip
=> "192.168.1.0"


Back to Text Conversion:
>> Rex::Text::compress("dfgdf dfgdfg ddddd")
=> "dfgdf dfgdfg ddddd"


Base-64 in/out:
>> Rex::Text::encode_base64("hello world",":::")
=> "aGVsbG8gd29ybGQ=:::"
>> Rex::Text::decode_base64("aGVsbG8gd29ybGQ=")
=> "hello world"


Gzip:
>> Rex::Text::gzip("hello world")
=> "\037\213\b\000\251\342\001J\002\003\313H\315\311\311W(\317/\312I\001\000\205\021J\r\v\000\000\000"


Awesome:
>> Rex::Text::hex_to_raw('\x20\x2e\x2f')
=> " ./"

>> Rex::Text::hexify("Metasploit rocks!Metasploit rocks!Metasploit rocks!")
=> "\\x4d\\x65\\x74\\x61\\x73\\x70\\x6c\\x6f\\x69\\x74\\x20\\x72\\x6f\\x63\\x6b\n\\x73\\x21\\x4d\\x65\\x74\\x61\\x73\\x70\\x6c\\x6f\\x69\\x74\\x20\\x72\\x6f\n\\x63\\x6b\\x73\\x21\\x4d\\x65\\x74\\x61\\x73\\x70\\x6c\\x6f\\x69\\x74\\x20\n\\x72\\x6f\\x63\\x6b\\x73\\x21\n"


>> Rex::Text::html_encode("http://www.google.com?ggg&4=4")
=> "&#x68&#x74&#x74&#x70&#x3a&
#x2f&#x2f&#x77&#x77&#x77&#x2e&
#x67&#x6f&#x6f&#x67&#x6c&#x65&
#x2e&#x63&#x6f&#x6d&#x3f&#x67&
#x67&#x67&#x26&#x34&#x3d&#x34"



Useful:
>> Rex::Text::md5("hello world!+")
=> "7eae149fd806efc3f80c44223205daeb"
>> Rex::Text::md5_raw("hello world!+")
=> "~\256\024\237\330\006\357\303\370\fD\"2\005\332\353"



>> Rex::Text::rand_base(20,'',"A")
=> "AAAAAAAAAAAAAAAAAAAA"


>> Rex::Text::rand_hostname
=> "rycc.bcn8y.n.f.moyn0oq9.org"

For fuzzing:
> Rex::Text::rand_text(40,'-')
=> "\025\263\022v\340o\3334\253EV.5\335KM[\204s(\362\371V\223\341\343Y\232\025P*\260\225l\e\223\317\342\314\275"


For network dumps:
>> Rex::Text::to_hex_dump("hello World\n")
=> "68 65 6c 6c 6f 20 57 6f 72 6c 64 0a hello World.\n\n"

>> Rex::Text::to_unescape("")
=> "%u673c%u6767%u413e"



>> Rex::Text::to_unicode("hello")
=> "h\000e\000l\000l\000o\000"

This is a nice framework to build testing and automated security and QA solutions around. I will revisit MSF Core API in the next post.

0 comments: