Fronting de domeniu pe baza TLS 1.3. Partea 2

Introducere

În prima parte recomandările sunt aplicabile coronavirusurilor în general și COVID-19 în particular. Așadar, recomand să descărcați și să printați articolul (pentru cei interesați de acest subiect). am oferit o descriere scurtă a mecanismului encrypted SNI (eSNI). Am arătat cum poate fi folosit pentru a evita detectarea de către sistemele moderne DPI (pe exemplul DPI-ului de la Beeline și al tracker-ului RuNet interzis), precum și am cercetat o nouă variantă de domain fronting bazată pe acest mecanism.

În a doua parte a articolului, ne vom concentra pe aspecte mai practice, care vor fi utile specialiștilor RedTeam în munca lor dificilă. În fond, scopul nostru nu este obținerea accesului la resursele blocate (pentru astfel de lucruri banale, avem vechiul și bunul VPN). Din fericire, există o mulțime de furnizori VPN, după cum se spune, pentru orice gust, culoare și buget.

Ne vom strădui să aplicăm mecanismul domain fronting pentru instrumentele moderne RedTeam, cum ar fi Cobalt Strike, Empire etc., și să le oferim funcționalități suplimentare de mimetizare și de evitare a sistemelor moderne de filtrare a conținutului.

Data trecută, am integrat mecanismul eSNI în biblioteca OpenSSL și l-am utilizat cu succes în binecunoscuta unealtă curl. Dar cu un singur curl, cum se spune, nu te poți sătura. Desigur, dorim să realizăm ceva similar în limbaje de programare de nivel înalt. Din păcate, căutarea rapidă pe internet ne dezamăgește, deoarece suportul pentru mecanismul eSNI este realizat pe deplin doar în GOLANG. Astfel, opțiunile noastre nu sunt foarte multe: fie scriem în C sau C++ folosind o bibliotecă OpenSSL patch-uită, fie folosim un fork GOLANG de la CloudFlare și încercăm să portăm instrumentele noastre acolo. De fapt, există o altă variantă, mai clasică, dar și mai consumatoare de timp – implementarea suportului eSNI pentru Python. În fond, Python folosește de asemenea OpenSSL pentru a lucra cu https. Dar această variantă o vom lăsa pentru dezvoltare altcuiva, în timp ce noi ne vom mulțumi cu implementarea în golang, mai ales că iubitul nostru Cobalt Strike este foarte bun în a lucra cu canale de comunicație construite prin mijloace externe (External C2 channel) – despre aceasta vom povesti la finalul articolului.

Try Harder…

Unul dintre instrumentele implementate pe Go este dezvoltarea noastră pentru pivotarea în rețea – tunelul rsockstun, care, de altfel, este acum detectată de soluțiile companiei Microsoft și Symantec ca un software extrem de dăunător, destinat să submineze stabilitatea globală…

Fronting de domeniu pe baza TLS 1.3. Partea 2

Ar fi grozav să utilizăm dezvoltarea anterioară și în acest caz. Dar aici apare o mică problemă. Problema este că rsockstun presupune inițial utilizarea unui canal de comunicare SSL sincronizat cu serverul. Aceasta înseamnă că conexiunea este stabilită o singură dată și există pe toată perioada de funcționare a tunelului. Și, după cum înțelegeți, protocolul https nu este chiar destinat acestui mod de funcționare – funcționează în modul cerere-răspuns, unde fiecare nouă cerere http există în cadrul unei noi conexiuni tcp.

Principala dezavantajă a acestui sistem este că serverul nu poate trimite date clientului până când clientul nu trimite o nouă cerere http. Dar, din fericire, există multe soluții pentru această problemă – pentru transmiterea continuă a datelor prin protocolul http (la urma urmei, reușim să ne uităm la serialele noastre preferate și să ascultăm muzică de pe portaluri care funcționează pe https, iar transmiterea video și audio nu este altceva decât transmiterea continuă a datelor). Una dintre tehnologiile de emulare a funcționării unei conexiuni tcp complete peste protocolul http este tehnologia websocket (WebSockets), al cărei principiu de bază este organizarea unei conexiuni complete între client și serverul web.

Din fericire (hurra!!!), această tehnologie este activată implicit în toate planurile tarifare CloudFlare și funcționează excelent în combinație cu eSNI. Tocmai aceasta vom folosi pentru a învăța tunelul nostru să utilizeze domeniul-frontend și să se ascundă de DPI moderne.

Câteva cuvinte despre WebSockets

În primul rând, vom explica pe scurt și în termeni simpli despre websocket-uri, pentru ca toată lumea să aibă o idee despre ce vom lucra.

Tehnologia websocket permite comutarea temporară de la o conexiune http la transmiterea standard a datelor printr-un socket de rețea, fără a întrerupe conexiunea tcp stabilită. Când clientul dorește să comute la websocket, acesta setează câteva antete http în cererea sa http. Două antete obligatorii sunt Connection: Upgrade și Upgrade: websocket. De asemenea, poate specifica forțat versiunea protocolului websocket (Sec-Websockset-Version: 13) și ceva asemănător unui identificator base64 pentru WebSocket (Sec-WebSocket-Key: DAGDJSiREI3+KjDfwxm1FA==). Serverul răspunde cu codul http 101 Switching Protocols și stabilește, de asemenea, anteturile Connection, Upgrade și Sec-WebSocket-Accept. Procesul de schimbare este ilustrat în captura de ecran de mai jos:

Fronting de domeniu pe baza TLS 1.3. Partea 2

După aceasta, stabilirea conexiunii WebSocket poate fi considerată finalizată. Orice date, atât de la client, cât și de la server, vor fi acum însoțite de anteturile WebSocket (care încep cu byte-ul 0x82). Acum serverul nu trebuie să aștepte o solicitare din partea clientului pentru a transmite datele, deoarece conexiunea TCP nu este întreruptă.

În Go, există mai multe biblioteci pentru a lucra cu WebSocket-uri. Cele mai populare dintre acestea sunt Gorilla WebSocket și standardul WebSocket. Vom folosi ultima, deoarece este mai simplă, mai mică și funcționează, se spune, puțin mai repede.

În codul clientului rsockstun, va trebui să înlocuim apelurile net.dial sau tls.dial cu apelurile corespunzătoare pentru WebSocket:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Fronting de domeniu pe baza TLS 1.3. Partea 2

Vrem să facem partea clientului din tunelul nostru universal și capabil să funcționeze atât printr-o conexiune SSL directă, cât și prin protocolul WebSocket. Pentru aceasta, vom crea o funcție separată func connectForWsSocks(address string, proxy string) error {…} similar cu connectForSocks() și o vom folosi pentru a lucra cu WebSocket-uri în cazul în care adresa serverului specificată la lansarea clientului începe cu ws: sau wss: (în cazul Secure WebSocket).

Pentru partea serverului tunelului, vom face de asemenea o funcție separată pentru a lucra cu WebSocket-uri. Aceasta va crea o instanță a clasei http și va seta un handler pentru conexiunea http (funcția wsHandler):

Fronting de domeniu pe baza TLS 1.3. Partea 2

Iar toată logica de procesare a conexiunii (autorizarea clientului prin parolă, stabilirea și încheierea sesiunii yamux) o vom plasa în handlerul de conexiune WebSocket:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Compilăm proiectul, lansăm partea serverului:

./rsockstun –listen ws:127.0.0.1:8080 –pass P@ssw0rd

Și apoi partea clientului:

./rsockstun -connect ws:127.0.0.1:8080 –pass P@ssw0rd

Și verificăm funcționarea pe localhost:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Fronting de domeniu pe baza TLS 1.3. Partea 2

Trecem la domeniul fronting

Cu WebSocket-urile am înțeles probabil cum stau lucrurile. Acum să trecem la eSNI și domeniul fronting. Așa cum am menționat mai devreme, pentru a lucra cu DoH și eSNI, trebuie să luăm o ramură specială a Go de la compania CloudFlare. Avem nevoie de o ramură cu suport pentru eSNI (pwu/esni).

O clonăm local sau o descărcăm și dezarhivăm zip-ul corespunzător:

git clone -b pwu/esni https://github.com/cloudflare/tls-tris.git

Apoi, trebuie să copiem directorul GOROOT, să înlocuim fișierele corespunzătoare din ramura clonată și să îl setăm ca principal. Pentru a scuti dezvoltatorul de această durere de cap, cei de la CloudFlare au pregătit un script special – _dev/go.sh. Pur și simplu îl lansăm. Scriptul, împreună cu makefile-ul, va face totul singur. De curiozitate – puteți arunca o privire în interiorul makefile-ului pentru detalii.

După ce scriptul a fost executat, la compilarea proiectului, va trebui să specificăm ca GOROOT directorul local pregătit de script. În cazul nostru, acest lucru arată astfel:

GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" go build ….

În continuare, trebuie să implementăm în tunel funcționalitatea de solicitare și analizare a cheilor eSNI publice pentru domeniul dorit. În cazul nostru, acestea vor fi cheile eSNI publice de la serverele front-end CloudFlare. Pentru aceasta, vom crea trei funcții:

func makeDoTQuery(dnsName string) ([]byte, error)
func parseTXTResponse(buf []byte, wantName string) (string, error)
func QueryESNIKeysForHost(hostname string) ([]byte, error)

Numele funcțiilor, în principu, vorbesc de la sine. Conținutul îl vom lua din fișierul esni_query.go, care face parte din tls-tris. Prima funcție creează un pachet de rețea cu o solicitare către serverul DNS CloudFlare, folosind protocolul DoH (DNS-over-HTTPS), a doua – analizează rezultatele solicitării și obține valorile cheilor publice ale domeniului, iar a treia este un container pentru primele două.

Apoi, introducem în funcția noastră, nou creată, de conectare a websocket-ului connectForWsSocks funcționalitatea de solicitare a cheilor eSNI pentru domeniu. Acolo unde funcționează partea serverului, setăm parametrii TLS și definim numele fals al „domeniului de acoperire”:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Trebuie menționat că inițial, ramura tls-tris nu este destinată utilizării domeniului-fronte. Prin urmare, nu se acordă atenție numelui fals al serverului (în cadrul pachetului client-hello se transmite un câmp serverName gol). Pentru a rezolva acest lucru, va trebui să adăugăm în structura TlsConfig câmpul corespunzător FakeServerName. Câmpul standard ServerName al structurii nu poate fi utilizat, deoarece este utilizat de mecanisme interne tls și, dacă va diferi de original, handshake-ul tls se va termina cu o eroare. Descrierea structurii TlsConfig se află în fișierul tls/common.go – acesta este fișierul pe care va trebui să-l corectăm:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Fronting de domeniu pe baza TLS 1.3. Partea 2

În plus, va trebui să facem modificări în fișierul tls/handshake_client.go, pentru a folosi câmpul nostru FakeServerName la formarea mânuței TLS:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Asta e tot! Poți compila proiectul și verifica funcționarea. Dar înainte de a începe testarea, trebuie să configurezi contul CloudFlare. Adică, cum să spun? Să creezi un cont pe CloudFlare și să asociezi domeniul tău cu acesta. Toate funcțiile legate de DoH, WebSocket și ESNI sunt activate în CloudFlare implicit. După ce înregistrările DNS s-au actualizat, poți verifica funcționarea domeniului executând solicitarea pentru cheile eSNI:

dig +short txt _esni.df13tester.info 

Fronting de domeniu pe baza TLS 1.3. Partea 2

Dacă vezi ceva similar pentru domeniul tău, asta înseamnă că totul funcționează și poți trece la testare.

Lansăm un VPS Ubuntu, de exemplu, pe DigitalOcean. P.S. În cazul nostru, adresa IP a VPS-ului, emisă recent de provider, s-a regăsit pe listele negre ale RKN. Așa că nu te mira dacă ți se întâmplă ceva similar. A fost necesar să folosim VPN pentru a accesa VPS-ul nostru.

Copiem pe VPS rsockstun compilat (de fapt, acesta este un alt avantaj al Golang-ului - poți compila proiectul pe sistemul tău și să-l rulezi pe orice Linux, respectând doar arhitectura sistemului) și lansăm partea serverului:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Apoi, partea client:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Așa cum vedem, clientul s-a conectat cu succes la server prin serverul frontend CloudFlare folosind WebSocket. Pentru a verifica că tunelul funcționează ca un adevărat tunel, poți face o solicitare curl prin socks5-ul local, deschis pe server:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Acum să vedem ce vede DPI în canalul de comunicare:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Întâi, tunelul, folosind mecanismul DoH, se adresează serverului DNS Cloudflare pentru cheile eSNI pentru domeniul de destinație (pachetele nr. 1-19), iar apoi accesează serverul frontend și stabilește o conexiune TLS, acoperindu-se cu acest domeniu www.google.com (aceasta este valoarea implicită când la lansarea clientului nu este specificat un domeniu fals). Pentru a specifica domeniul tău fals, este necesar să folosești parametrul -fronfDomain:

Fronting de domeniu pe baza TLS 1.3. Partea 2

Fronting de domeniu pe baza TLS 1.3. Partea 2

Acum o altă problemă. Implicit, în setările contului de pe CloudFlare este activat modul de funcționare Flexible SSL. Aceasta înseamnă că solicitările https către serverele frontend Cloudflare de la clienți vor fi redirecționate în formă necriptată (http) către serverul nostru. De aceea am lansat partea serverului tunelului în modul non-ssl (-listen ws:0.0.0.0), nu (-listen wss:0.0.0.0).

Fronting de domeniu pe baza TLS 1.3. Partea 2

Pentru a trece în modul de criptare completă, este necesar să alegi Full, sau Full (strict) în cazul în care există un certificat real pe server. După schimbarea modului, vom putea accepta conexiuni de la CloudFlare prin protocolul https. Nu uitați să generați un certificat auto-semnat pentru partea de server a tunelului.

Fronting de domeniu pe baza TLS 1.3. Partea 2

Un cititor perspicace ar întreba: „Și ce se întâmplă cu clientul pentru Windows? Cu siguranță, utilizarea principală a tunelului este pentru a stabili o conexiune de back cu mașinile și serverele corporative, iar acolo, de regulă, există întotdeauna Windows. Cum pot să compilez tunelul pentru Windows, și încă cu o stivă specifică TLS?” Și acum să prezentăm încă o caracteristică care arată cât de convenabil este Go. Compilăm pentru Windows direct din Kali, adăugând pur și simplu parametrul GOOS=windows:

GOARCH=amd64 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w"

Sau variantă pe 32 de biți:

GOARCH=386 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w"

Totul! Și nu mai trebuie să vă faceți griji. Chiar funcționează!

Fronting de domeniu pe baza TLS 1.3. Partea 2

Flagurile de compilare –w și –s sunt necesare pentru a elimina gunoiul din fișierul executabil, făcându-l mai mic cu câteva megabytes. În plus, ulterior poate fi împachetat cu ajutorul UPX, pentru a reduce și mai mult dimensiunea.

În concluzie

În articol, prin exemplul tunelului scris în Go, am demonstrat aplicarea noului concept de domeniu-frontal, realizat pe o caracteristică destul de interesantă a protocolului TLS 1.3. În mod similar, se poate adapta instrumentarul existent scris în Go pentru a funcționa prin serverele CloudFlare, de exemplu. Merlin — un C2 cunoscut, sau să forțăm CobaltStrike Beacon să utilizeze domeniu-frontal eSNI când lucrează cu Teamserver prin Canal C2 extern, realizat în Go, sau pe standardul C++ folosind o versiune patch-uită a OpenSSL, despre care am vorbit în partea anterioară a articolului. În general, fantezia nu are limite.

Exemplul cu tunelul și CloudFlare este prezentat ca o concepție și, deocamdată, este greu de spus despre perspectivele pe termen lung ale acestui tip de domeniu-frontal. În prezent, suportul eSNI este realizat doar de CloudFlare și, teoretic, nimic nu îi oprește să dezactiveze acest tip de frontare și, de exemplu, să rupă conexiunile TLS în cazul necorespunderii SNI și eSNI. În general, viitorul va arăta. Dar deocamdată, perspectiva de a opera sub „acoperirea kremlin.ru” pare destul de tentantă. Nu-i așa?

Codul actualizat al tunelului, precum și fișierele executabile exe compilate sunt disponibile într-o ramură separată a proiectului pe github. Pentru toate problemele posibile ale tunelului, este recomandat să scrieți un issue pe pagina proiectului de pe GitHub.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster