Writing Meterpreter Extensions

Railgun and other meterpreter functionality is awesome and can do almost everything you would like on a compromised system, but sometimes, due to performance or bandwidth requirements or just weird threading issues, you need to be able to run compiled code on a target. You can upload an executable to a system and run that, but you really shouldn't if you don't have to; uploading an executable just gives you another opportunity to get caught and more to clean up after yourself. What you should do is write a meterpreter extension. There are not many guides on how to do that, so to save you some time, you can use as an example two extensions I have written. Visual Studio 2008 will be a prerequisite to build the solution.

All the necessary changes can be seen in either of the extensions' initial commits, for the webcam extension (which has now been incorporated into stdapi and is no longer a separate extension) here: https://dev.metasploit.com/redmine/projects/framework/repository/revisions/db602dd478ebe5befb7fdbbb45d30f951812a52d and the lanattacks extension, added as part of the recent PXE work here: https://dev.metasploit.com/redmine/projects/framework/repository/revisions/b2733c04dbe72c3c4b8846724eaf700062e9fa74.

Compiled Extension

First copy the project folder and file of an existing project to a new location; I used espia for webcam, but you can use whatever you want, like incognito, which is also not too complicated:

C:\Program Files (x86)\Rapid7\framework\msf3>xcopy /E external\source\meterpreter\source\extensions\incognito external\source\meterpreter\source\extensions\mynewextension\
C:\Program Files (x86)\Rapid7\framework\msf3>xcopy /E external\source\meterpreter\workspace\ext_server_incognito external\source\meterpreter\workspace\ext_server_mynewextension\

In my opinion, it is easier to simply open up the project file in a text editor and find/replace all occurrences of incognito with mynewextension than to manually change them all in Visual Studio, so move external\source\meterpreter\workspace\ext_server_mynewextension\ext_server_incognito.vcproj to external\source\meterpreter\workspace\ext_server_mynewextension\ext_server_mynewextension.vcproj, then open it in a text editor and do the find/replace. That will ensure the output .dll will be appropriately named, the project will look in the right folders for source files and headers, and it will generate intermediate object files in the right directory. Then change the ProjectGUID at the top to a random GUID.

Now you need to add the new project to your solution, so open up the meterpreter solution in Visual Studio 2008 and add this project. Important - You need to add project dependencies of common, ReflectiveDLLInjection, and metsrv for the project to compile; right-click on the solution, open properties, select your project, and check the boxes at the bottom for those three projects. (alternatively, if you hate GUI's and love text editors, make the same additions as in this diff just replace {2FCCCE33-77E9-43F3-928E-DBF6B9340A62} with your new GUID.)

Now you can start writing your code! Feel free to remove most of the .c and .h files or add your own, just be sure to keep the main .c and .h files; in incognito, those are incognito.c and incognito.h; in webcam those are main.c and main.h although you can rename those. This should go without saying, but before you write, make sure you have thought about design: you will need to decide what functions you will implement and the arguments and types of arguments that each of those functions will take and return. Those functions will be reported to the meterpreter controller in the main .c file in the InitServerExtension function. You should only need to edit the customCommands[] array, which links a function name, e.g. "webcam_start" with a function e.g. request_webcam_start. See example. The types you use will be defined in the primary .h file for your extension (example). Be sure to use your own function names! Each of the functions must return a DWORD and take two arguments: a pointer to a Remote struct you probably won't use and a pointer to a Packet struct.

DWORD request_webcam_list(Remote *remote, Packet *packet)

If you want to use C++, as I did to interact with the webcam APIs, place these functions into an extern "C" block (see video.cpp) To get the fields sent in your request packet, use the packet_get_tlv_* functions with the type you have defined, for example

UINT index = packet_get_tlv_value_uint(packet, TLV_TYPE_WEBCAM_INTERFACE_ID);

There are also other functions appropriate to the type of your fields defined in external/source/meterpreter/source/common/channel.c

LINKAGE PCHAR packet_get_tlv_value_string(Packet *packet, TlvType type); 
LINKAGE UINT packet_get_tlv_value_uint(Packet *packet, TlvType type);
LINKAGE BYTE * packet_get_tlv_value_raw( Packet * packet, TlvType type );
LINKAGE QWORD packet_get_tlv_value_qword(Packet *packet, TlvType type);
LINKAGE BOOL packet_get_tlv_value_bool(Packet *packet, TlvType type); 

When you've done your magic you need to send a response packet back.

	Packet *response = packet_create_response(packet);
	packet_transmit_response(res, remote, response);

And to return all the juicy data back to the meterpreter controller, you can add fields to the response packet, just like you got them from the request packet before sending:

	packet_add_tlv_raw(response, TLV_TYPE_LANATTACKS_RAW, log, loglen);

Remember to compile in Release mode (Debug usually doesn't work) for both x86 and x64, then copy your generated .dll's to the data/meterpreter/ folder.

Ruby Controller

Now that you have your amazing extension, you need to be able to load and control it from Metasploit. First you'll need to define your types in ruby, just like you did in C, in lib/rex/post/meterpreter/extensions/mynewextension/tlv.rb, example.

Next, define a class that will serve as the controller internally to Metasploit, in lib/rex/post/meterpreter/extensions/mynewextension/mynewextension.rb; you can copy the webcam file and do a find/replace of webcam with your extension name. Then edit the functions to correspond to the functions you defined in the compiled extension. You can use Packet.create_request and request.add_tlv to create the request. Then call client.send_request, which will return the response packet and use response.get_tlv to get data from the response.

Your extension is now available for writing post modules or exploits! If you want to add console commands, add a file to lib/rex/post/meterpreter/ui/console/command_dispatcher/ and feel free to base it on the webcam.rb file. The commands method must return a hash of the commands you will provide mapped to a short description of each, for example {"webcam_list" => "List webcams"}. For each of these commands, you need to implement a method to receive the commands, for example cmd_webcam_list. You can see how to do arguments in the cmd_webcam_snap function. Be sure to use the print_line, print_error, etc. functions to display output instead of puts, so your output will be displayed in all the UI's and follow the other instructions in the HACKING file.


Metasploit is an open-source project, so if you have enjoyed what all the devs have done, and you just made something really cool, why not share your amazing new extension? Post a ticket to the redmine tracker at https://dev.metasploit.com/redmine/projects/framework or post it to the mailing list or come talk to us on the IRC channel.

, ,

  1. #1 by Scott Behrens on August 29, 2011 - 2:20 pm

    This is great, thanks for documenting this. I’m currently working through the equivalent with the posix meterpreter and custom extensions which has also been a bit of a challenge!

  2. #2 by darklord on November 27, 2011 - 6:40 am

    hello sir..nice tuts..I want to know how I can use my Metasploit (running on BT5 VM) to pentest global IP addresses. When I use a client side exploit then the link/file it generates belongs to the local IP of my system.. so I can only use them to test my LAN only. Can you help me with this.

Comments are closed.