Uvod
U prvom dijelu dali smo kratak pregled mehanizma encrypted SNI (eSNI). Pokažemo kako se na temelju njega može izbjegavati otkrivanje modernim DPI sustavima (na primjer, Beelineovog DPI-a i zabranjenog RKN rutrekera), kao i istražili novu varijantu domen-fronitnga na temelju ovog mehanizma.
U drugom dijelu članka preći ćemo na praktične stvari koje će biti korisne RedTeam stručnjacima u njihovom teškom radu. Naša svrha u konačnici nije pristup blokiranim resursima (za takve trivijalne stvari imamo našu dobru staru VPN uslugu). Na sreću, postoji mnogo VPN provajdera, kako se kaže, za svaki ukus, boju i proračun.
Pokušat ćemo primijeniti mehanizam domen-fronitnga na moderne alate RedTeam-a, kao što su Cobalt Strike, Empire itd., i pružiti im dodatne mogućnosti mimikriranja i izbjegavanja modernih sustava filtriranja sadržaja.
Prošli put smo implementirali mehanizam eSNI u OpenSSL biblioteku i uspješno ga koristili u svima poznatom alatu curl. No, samo s curlom, kako se kaže, ne može se dugo preživjeti. Naravno, želimo ostvariti nešto slično na visokim programskim jezicima. Nažalost, brzi pregled interneta nas razočarava jer je podrška za mehanizam eSNI potpuno implementirana samo u GOLANG-u. Tako da, naš izbor nije prevelik: ili pišemo na čistom C-u ili C++-u koristeći propatched OpenSSL biblioteku, ili koristimo zasebni CloudFlare GOLANG fork i pokušavamo portirati naš alat tamo. U načelu, postoji još jedna opcija, klasičnija, ali istovremeno i mukotrpnija - implementirati podršku za eSNI u Pythonu. Uostalom, Python također koristi OpenSSL za rad s https. No tu opciju ćemo ostaviti za nekog drugog, a sami ćemo biti zadovoljni implementacijom na GOLANG-u, pogotovo jer naš omiljeni Cobalt Strike odlično surađuje s vanjskim komunikacijskim kanalima (External C2 channel) – o tome ćemo govoriti na kraju članka.
Pokušajte jače...
Jedan od alata implementiranih na GOLANG-u - naše rješenje za pivotiranje unutar mreže - tunel , koja se, usput budi rečeno, trenutno detektira alatima kompanija Microsoft i Symantec kao vrlo zlonamjerni softver usmjeren na narušavanje globalne stabilnosti…

Bilo bi sjajno iskoristiti prethodni razvoj i u ovom slučaju. Međutim, tu se javlja mali problem. Naime, rsockstun prvotno podrazumijeva korištenje sinkronog SSL kanala za komunikaciju sa serverom. To znači da se veza uspostavlja samo jednom i postoji tijekom cijelog vremena rada tunelera. Kao što znate, HTTPS protokol nije baš namijenjen takvom načinu rada – on radi u režimu zahtjev-odgovor, gdje svaki novi HTTP zahtjev postoji u okviru nove TCP veze.
Glavni nedostatak takve sheme je u tome što server ne može poslati podatke klijentu dok klijent ne pošalje novi HTTP zahtjev. No, srećom, postoje različita rješenja za ovaj problem – streaming podataka putem HTTP protokola (na kraju krajeva, uspijevamo gledati omiljene serije i slušati muziku s portala koji rade na HTTPS-u, a prijenos videa i zvuka nije ništa drugo nego streaming podataka). Jedna od tehnologija za emulaciju rada punopravne TCP veze preko HTTP protokola je tehnologija web soketa (WebSockets), čija je osnovna ideja organizacija punopravne mrežne veze između klijenta i web servera.
Našu sreću (ura!!!), ova tehnologija je uključena po defaultu u sve planove CloudFlare i savršeno radi u kombinaciji s eSNI. Upravo tu ćemo je iskoristiti da naučimo naš tuneler kako da koristi domen-fronting i sakrije se od modernih DPI.
Malo o WebSockets
Prije svega, ukratko i jednostavnim riječima objasnit ćemo web sokete, kako bi svi imali predstavu o tome s čime ćemo raditi.
Tehnologija web soketa omogućava privremeno prebacivanje s HTTP veze na standardni streaming podataka putem mrežnog soketa, ne prekidajući pri tome uspostavljenu TCP vezu. Kada klijent želi prebaciti na web soket, u svom HTTP zahtjevu postavlja nekoliko HTTP zaglavlja. Dva obavezna zaglavlja su Connection: Upgrade i Upgrade: websocket. Također može obavezno navesti verziju WebSocket protokola (Sec-Websockset-Version: 13) i nešto poput base64 identifikatora web-soketa (Sec-WebSocket-Key: DAGDJSiREI3+KjDfwxm1FA==). Poslužitelj odgovara s http-kodom 101 Switching Protocols i također postavlja zaglavlja Connection, Upgrade i Sec-WebSocket-Accept. Proces prebacivanja jasno je prikazan na slici ispod:

Nakon toga, uspostava WebSocket veze može se smatrati završenom. Sve podatke, kako od klijenta tako i od poslužitelja, sada će pratiti ne http, nego WebSocket zaglavlja (počinju s bajtom 0x82). Sada poslužitelju nije potrebno čekati zahtjev od klijenta da bi poslao podatke, jer tcp-veza se ne prekida.
U Go-u za rad s web-soketima dostupne su nekoliko biblioteka. Najpopularnije su i standardna . Iskoristit ćemo posljednju, jer je jednostavnija, manja i radi, kako kažu, malo brže.
U klijentskom kodu rsockstun trebamo zamijeniti pozive net.dial ili tls.dial s odgovarajućim pozivima WebSocket:


Želimo učiniti klijentski dio našeg tunelera univerzalnim i sposobnim raditi kako preko direktne ssl-veze, tako i preko WebSocket protokola. U tu svrhu stvorit ćemo posebnu funkciju func connectForWsSocks(address string, proxy string) error {…} po analogiji s connectForSocks() i koristit ćemo je za rad s web-soketima u slučaju da adresa poslužitelja, navedena prilikom pokretanja klijenta, počinje s ws: ili wss: (u slučaju Secure WebSocket-a).
Za poslužiteljsku stranu tunelera također ćemo napraviti posebnu funkciju za rad s web-soketima. U njoj će se stvarati instanca klase http i postavljati će se handler za http-vezu (funkcija wsHandler):

A svu logiku obrade veze (autorizaicija klijenta imenom i lozinkom, uspostavljanje i završetak yamux sesije) smjestit ćemo u handler za WebSocket vezu:

Kompajliramo projekt, pokrećemo poslužiteljsku stranu:
.\/rsockstun –listen ws:127.0.0.1:8080 –pass P@ssw0rdA zatim klijentsku stranu:
.\/rsockstun -connect ws:127.0.0.1:8080 –pass P@ssw0rdI provjeravamo rad na lokalnom računalu:


Prelazimo na domen-frotning
Čini se da smo shvatili web-sokete. Sada prijeđimo na eSNI i domen-frotning. Kao što je ranije spomenuto, za rad s DoH i eSNI potrebno je uzeti posebnu granu Go-a od tvrtke . Potrebna nam je grana s podrškom za eSNI (pwu/esni).
Kloniramo je lokalno ili preuzimamo i raspakiravamo odgovarajući zip:
git clone -b pwu/esni https://github.com/cloudflare/tls-tris.gitZatim trebamo kopirati katalog GOROOT, zamijeniti odgovarajuće datoteke iz klonirane grane i postaviti ga kao glavni. Kako bismo olakšali život programerima, dečki iz CloudFlarea pripremili su poseban skript – _dev/go.sh. Jednostavno ga pokrenite. Skript zajedno s makefileom sve će obaviti sam. Za zanimaciju — možete zaviriti unutra makefilea za detalje.
Nakon što skript završi, prilikom kompajliranja projekta, trebamo navesti lokalni katalog, pripremljen skriptom, kao GOROOT. U našem slučaju to izgleda ovako:
GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" go build ….Nadalje, trebamo implementirati funkcionalnost zahtjeva i parsiranja javnih eSNI ključeva za potrebnu domenu u tunel. U našem slučaju, to će biti javni eSNI ključevi s front-end poslužitelja CloudFlarea. Za to ćemo stvoriti tri funkcije:
func makeDoTQuery(dnsName string) ([]byte, error)
func parseTXTResponse(buf []byte, wantName string) (string, error)
func QueryESNIKeysForHost(hostname string) ([]byte, error)Nazivi funkcija, u načelu, govore sami za sebe. Podaci ćemo uzeti iz datoteke esni_query.go, koja je dio tls-tris. Prva funkcija stvara mrežni paket s upitom na DNS poslužitelj CloudFlarea, koristeći DoH protokol (DNS-over-HTTPS), druga – parsira rezultate upita i dobiva vrijednosti javnih ključeva domene, a treća je kontejner za prve dvije.
Nadalje, dodajemo u našu, ponovno stvorenu, funkciju za povezivanje web-socketa connectForWsSocks funkcionalnost zahtjeva eSNI ključeva za domenu. Tamo gdje funkcionira poslužiteljski dio, postavljamo TLS parametre i određujemo ime lažne 'domene pokrića':

Valja napomenuti da je prvotno, grana tls-tris nije predviđena za primjenu domenskog frontinga. Stoga, nije obraćeno pažnja na lažno ime poslužitelja (u okviru client-hello paketa prenosi se prazno polje serverName). Da bismo to ispravili, morat ćemo dodati odgovarajuće polje FakeServerName u strukturu TlsConfig. Standardno polje ServerName u strukturi ne možemo koristiti, jer ga koriste unutarnji mehanizmi tls i ako se razlikuje od izvorne, tls handshake završit će greškom. Opis strukture TlsConfig nalazi se u datoteci tls/common.go – to ćemo morati ispraviti:


Osim toga, morat ćemo unijeti promjene u datoteku tls/handshake_client.go, kako bismo koristili naše polje FakeServerName pri formiranju TLS rukovanja:

To je to! Možete kompilirati projekt i provjeriti njegov rad. No prije pokretanja provjere, potrebno je postaviti CloudFlare račun. Pa, kako da kažem postaviti – samo kreirati račun na CloudFlare i povezati svoju domenu s njim. Sve značajke vezane za DoH, WebSocket i ESNI su po defaultu uključene u CloudFlare. Nakon što se DNS zapisi ažuriraju – možete provjeriti funkcionalnost domene izvršavanjem upita za eSNI ključeve:
dig +short txt _esni.df13tester.info 
Ako vidite nešto slično za vašu domenu – to znači da sve funkcionalno radi i možete preći na testiranje.
Pokrećemo Ubuntu VPS, na primjer, na DigitalOcean. P.S. U našem slučaju, netom dodijeljena IP adresa VPS-a od strane davatelja nalazila se na crnoj listi RKN. Dakle, ne čudite se ako vam se dogodi nešto slično. Morali smo koristiti VPN kako bismo pristupili svom VPS-u.
Kopiramo već kompilirani rsockstun na VPS (usput, još jedna prednost GoLang-a – možete kompilirati projekt kod sebe i pokrenuti ga na bilo kojem Linuxu, zadržavajući samo arhitekturu sustava) i pokrećemo serverski dio:

A zatim klijentski dio:

Kao što vidimo, klijent se uspješno povezao sa serverom putem CloudFlare frontend servera koristeći web socket. Da bismo provjerili da tunel radi kao tunel, možemo izvršiti curl upit preko lokalnog socks5, otvorenog na serveru:

Sada ćemo pogledati što DPI vidi u komunikacijskom kanalu:

Prvo tunel, koristeći DoH mehanizam obraća se DNS serveru Cloudflare za eSNI ključeve za ciljani domen (paketi br. 1-19), a zatim se obraća frontend serveru i uspostavlja TLS vezu, prikrivajući se tom domenom (to je zadana vrijednost kada se klijent pokrene bez postavljenog lažnog domena). Da biste odredili svoj lažni domen potrebno je koristiti parametar -fronfDomain:
![]()

Sada još jedan važan trenutak. Po defaultu, u postavkama računa na CloudFlare postavljen je fleksibilni SSL. To znači da će https upiti klijenata prema CloudFlare frontend serverima biti preusmjereni u nekriptiranom (http) formatu našem serveru. Zato smo pokrenuli serverski dio tunelera u non-ssl režimu ( -listen ws:0.0.0.0), a ne ( -listen wss:0.0.0.0).

Da biste prešli u režim pune enkripcije potrebno je odabrati Full, ili Full (strict) u slučaju da je na serveru prisutan važeći certifikat. Nakon prebacivanja načina rada, moći ćemo primati veze od CloudFlare putem https protokola. Ne zaboravite generirati self-signed certifikat za serversku stranu tunelera.

Zanesen čitatelj će pitati: „A što je s klijentom za Windows? Sigurno je da je osnovna primjena tunelera podizanje bek-konekcije s korporacijskim računalima i serverima, a tamo je obično uvijek Windows. Kako mogu kompajlirati tuneler za Windows, a da još bude s određenim TLS stakom?“ Sada ćemo predstaviti još jednu značajku koja pokazuje koliko je Go zgodan. Kompajliramo za Windows iz Kalia, jednostavno dodajući parametar GOOS=windows:
GOARCH=amd64 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w"Ili 32-bitna varijanta:
GOARCH=386 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows go build -ldflags="-s -w"Sve! I više nikakvih briga nije potrebno. To stvarno radi!

Kompajlerske zastavice –w i –s su potrebne za uklanjanje suvišnog otpada iz izvršne datoteke, čineći je manjom za nekoliko megabajta. Dodatno je kasnije moguće upakovati s UPX-om, kako bi se dodatno smanjila veličina.
Umjesto zaključka
U članku smo, koristeći primjer tunelera napisanog u Go, demonstrirali primjenu nove tehnologije domen-frontinga, realizirane na prilično zanimljivoj osobini protokola TLS 1.3. Sličnim putem se može prilagoditi postojeći alat napisan u Go za rad putem CloudFlare servera, na primjer — poznati C2, ili natjerati CobaltStrike Beacon da koristi eSNI domen-fronting prilikom rada s Teamserverom putem , realiziranog u Go-u, ili pak u standardnom C++ s korištenjem patchirane verzije OpenSSL-a, o kojoj smo govorili u prethodnom dijelu članka. Ukratko, mašti nema kraja.
Primjer s tunelerom i CloudFlare predstavljen je u obliku koncepta, a za sada je teško reći o daljnjim perspektivama takvog tipa domen-frontinga. Trenutno je podrška za eSNI implementirana samo kod CloudFlare-a i, u teoriji, ništa im ne može zabrani da isključe takvu vrstu frontinga i, na primjer, prekinu tls-veze u slučaju neskladnosti između SNI i eSNI. U konačnici, budućnost će pokazati. No za sada perspektiva rada pod „pokrićem kremlin.ru“ izgleda prilično primamljivo. Nije li tako?
Ažurirani kod tunelera, kao i kompajlirani izvršni exe-fajlovi su dostupni u posebnom ogranku projekta na . O svim mogućim problemima s tunelerom najbolje je pisati issue na stranici projekta na GitHubu.
Izvor: habr.com
