TL; DR
En Maven Central-artefakt publisert som io.github.davidtimur:c2-lab sendte ut ni utgivelser, hvorav åtte utførte en nyttelast for fjerntilgang under kompileringen av et hvilket som helst nedstrømsprosjekt som plasserte jar-filen på sin annotasjonsprosessorbane. Ingen applikasjonskode måtte importere den. Ingen kildekode måtte referere til den. Det fantes ikke noe installasjonsskript, ingen tilsvarende etterinstallasjon, og ingen livssykluskrok av noe slag som verktøy kunne inspisere.
Utførelsesvektoren er en enkelt 46-byte-fil inne i jar-filen: en Java-tjenesteleverandørregistrering som navngir en klasse som implementerer javax.annotation.processing.ProcessorJava-kompilatoren oppdager slike registreringer automatisk. Når de er funnet, javac instansierer og kjører klassen som en vanlig del av kompileringen. Det betyr at nyttelastens kjøretidsmiljø er byggemaskinen, i det øyeblikket byggemaskinen gjør den ene tingen den eksisterer for å gjøre.
I løpet av de ni utgivelsene ble kommando- og kontrollkanalen gjenoppbygd tre ganger: en operatørlevert tilbakeringings-URL, deretter et omvendt skall over en ngrok TCP-tunnel, og deretter en HTTP-avstemningskanal hvis stier ble endret to ganger til. Den endelige utgivelsen installerte en no-op TLS-tillitsbehandler som JVM-standard, akseptere ethvert sertifikat i løpet av kompileringen.
Gjenstanden hadde ordene «C2 Lab Payload» i sin egen POM og en MIT-lisens. Den var aktiv på Maven Central i hele perioden vi observerte den, og har siden blitt fjernet, sammen med hele io.github.davidtimur gruppen.
Anatomi: kompilatoren som utførelsesmotor
Javas rammeverk for annoteringsbehandling finnes slik at biblioteker kan generere kode ved kompilering – mekanismen bak Lombok, Dagger og en lang liste med ORM- og serialiseringsverktøy. En prosessor annonserer seg selv med en ren tekstfil inne i jar-filen:
META-INF/tjenester/javax.annotasjon.behandling.Prosessor
Innholdet i den filen i alle berørte utgivelser, ordrett og fullstendig:
io.github.davidtimur.c2lab.C2Processor
Filen er byte-identisk på tvers av versjon 1.0.1 til 1.0.8, md5 7d2a08a5c8869a47eea9fa62487dfbe4. Versjon 1.0.0 inneholder den ikke.
Når Javac Når den kjører, skanner den annoteringsprosessorbanen for disse tjenesteoppføringene og laster inn det den finner. Ingenting i prosjektet som kompileres trenger å nevne prosessoren, annotere noe eller konfigurere noe. Tilstedeværelse på banen er tilstrekkelig. Dette er egenskapen som skiller JavacDoor fra forsyningskjedemønstrene som de fleste verktøy er bygget rundt:
| Pattern | Avtrekker | Synlig som |
|---|---|---|
| npm installasjonskrok | npm install | scripts.postinstall i manifestet |
| Python-nyttelast ved importtid | første import av modulen | modulnivåsetning i kildekode |
| JavacDør | javac på ethvert nedstrømsprosjekt | et filnavn for tjenesteregistrering |
En installasjonshook er en deklarasjon i et manifest, og et manifest er det første noen leser. En nyttelast ved import ligger i det minste i en lesbar kildekode. En tjenesteregistrering er ingen av delene: det er et filnavn pluss én linje som navngir en klasse, og oppførselen ligger i en kompilert bytekode en mappe unna.
Nyttelastklassen utfører selve vertsrekognosering ved å sende ut signaler. Konstantpoolene til de kompilerte klassene inneholder / Bin / sh, whoami, uname -a, pwd på Unix-stien og tasklist på Windows-banen, sammen med omdirigeringsfeilstrøm å slå sammen feilutdataene fra barneprosessen med den innsamlede strømmen. To JSON-maler overfører resultater fra verten – et registreringsbeacon:
{"host":"%s","os":"%s","user":"%s","dir":"%s"}
befolket fra vertsnavn kommandoen og os.navn, brukernavnog bruker.dir systemegenskaper og et tilbakekall av et resultat:
{"version":"%s","host":"%s","time":"%s","output":"%s"}
Fremdriftsmarkørene som er igjen i kompilatorens egen utdata er uvanlig åpenbare: [C2] kompileringstidsutførelse fullført, [C2] tilbakeringing sendt → HTTP , [C2] skall koblet til .
Ni utgivelser, tre C2-generasjoner
Utgivelsene er ikke ni kopier av én nyttelast. De er en iterasjonslogg, og å lese dem i rekkefølge viser at kanalen blir gjenoppbygd mens leveringsvektoren forble fast.
| Slipp | Autokjører ved kompilering | Kanal |
|---|---|---|
1.0.0 | nei (ingen tjenestefil) | Kun operatørlevert tilbakeringings-URL |
1.0.1 | ja (vektor introdusert) | Operatørlevert tilbakeringings-URL |
1.0.2 | ja | Omvendt skall, ngrok TCP-tunnel |
1.0.3 | ja | HTTP-kanal, /register /cmd /out |
1.0.4 | ja | HTTP-kanal, /register /cmd /out |
1.0.5 | ja | HTTP-kanal, /register /poll /out |
1.0.6 | ja | HTTP-kanal, /register /poll /out |
1.0.7 | ja | HTTP-kanal, /register /cmd |
1.0.8 | ja | HTTP-kanal + TLS-validering deaktivert |
Tre detaljer i den tabellen er verdt å trekke frem, fordi hver enkelt endrer hvordan artefaktsettet skal leses.
Vektoren ankommer til 1.0.1, ikke 1.0.2. Versjon 1.0.0 har samme rekognoserings- og tilbakekallingslogikk, men har ingen tjenestefil og ingen import for annotasjonsbehandling; den kjører bare hvis noe kaller den. Fra 1.0.1 er tjenestefilen til stede, og de kompilerte klassene importeres javax.annotation.processing.Støttet kildeversjonEnhver vurdering som sammenligner de to utgivelsene med billett – 1.0.0 og 1.0.2 – konkluderer riktig med at noe har endret seg, men feilaktig identifiserer hvor.
Det omvendte skallet finnes i nøyaktig én utgivelse. Versjon 1.0.2 inneholder 0.tcp.ngrok[.]io, logglinjen [C2] skall koblet til 0.tcp.ngrok[.]io:19823, et interaktivt banner c2-skall, og en rammeterminator __SLUTT__Utgivelser 1.0.3 og utover inneholder ingen av disse, og når i stedet en HTTPS-vert. En fjerningsforespørsel som bare navngir de utgivelsene med billett, ville ha sitert et dødt TCP-endepunkt, mens den aktive HTTP-kanalen, som finnes i seks senere utgivelser, ikke ble nevnt.
Den endelige utgivelsen fjerner transportverifisering. Versjon 1.0.8 legger til en klasse som implementerer javax.net.ssl.X509TrustManager hvis sertifikatkontrollmetoder ikke gjør noe, en alltid-sann vertsnavnverifikator registrert gjennom angiStandardvertsnavnVerifiserOg stol på alle rutine som installerer begge som JVM-ens standardinnstillinger. Effekten er at for resten av kompileringen godtar JVM-en ethvert sertifikat fra enhver vert – ikke bare for nyttelastens egen trafikk, men for alt annet byggingen gjør over TLS etterpå.
HTTP-kanalen, i alle seks utgivelser som bruker den, er frontet av en enkelt vert: tableful-fervor-crazed.ngrok-free[.]devHver forespørsel har overskriften ngrok-skip-browser-advarsel, som undertrykker den mellomliggende siden som gratis ngrok-tunneler viser til nettlesere. Stisett endres på tvers av utgivelser — /ute forsvinner ved 1.0.7, og /cmd veksler med /avstemming – men verten forandrer seg aldri.
Selvutestengingen forteller
Hver POM fra 1.0.1 og utover setter et kompilatorargument for artefaktens egen bygging:
-pros:ingen
Det flagget deaktiverer annoteringsbehandling. Effekten her er forhåndsbestemt.cise: når prosjektet som inneholder prosessoren i seg selv kompileres, kjører ikke prosessoren.
Dette flagget har helt vanlige bruksområder. Et prosjekt som leverer en annotasjonsprosessor trenger ofte å unngå å bruke den prosessoren på seg selv under oppstart, og dokumentasjonen for byggeverktøyet anbefaler nettopp dette. Alene beviser det ingenting.
Sammen med hva prosessoren gjør, beskriver det imidlertid en spesifikk asymmetri: koden kjøres på maskinene til alle som kompilerer mot artefakten, og ikke på maskinen som bygger artefakten. Flagget vises i samme utgivelse som introduserer tjenestefilen – 1.0.1 – og i hver utgivelse etter den. Korrelasjonen mellom «utgivelsen der kompileringstidskjøringen begynner» og «utgivelsen der kompileringstidskjøringen er slått av lokalt» er det mest nyttige analytiske signalet i artefaktsettet, og det er synlig i en ren tekst-POM uten å dekompilere noe.
Vi legger merke til effekten og stopper der. Ingenting i gjenstandene sier noe om hvorfor flagget ble satt opp.
En annen metadatadel fortjener å nevnes, hovedsakelig for å kvitte seg med den. POM kaller prosjektet «C2 Lab Payload», beskriver det som en «C2 lab payload artefakt» og lisensierer det til MIT. Selvmerking av denne typen tilbys noen ganger som bevis på at en pakke er en forskningsøvelse.cise snarere enn en levende trussel, og av og til er den lesningen riktig – en deklarert kanarifugl uten tilgjengelig infrastruktur er et annet objekt enn dette. Det gjelder ikke her. Et funksjonelt implantat publisert til et offentlig arkiv, tilgjengelig for enhver forbruker, med utgående infrastruktur som ble gjenoppbygd tre ganger på tvers av ni utgivelser, er en levende funksjon uavhengig av hva metadataene kaller den. Navnet i POM endrer ingenting om hva som skjer på en maskin som kompilerer mot den.
Indikatorer for byggemaskiner
Hvis en byggevert kompilerte mot denne artefakten, ligger bevisene i byggelogger og nettverkstelemetri i stedet for i et vedvarende implantat på disk – nyttelasten kjører inne i kompileringsprosessen og avsluttes med den.
I jar-filen eller den lokale hurtigbufferen for arkivet
META-INF/services/javax.annotation.processing.Processornavngivingio.github.davidtimur.c2lab.C2Processor- Tjenestefil md5
7d2a08a5c8869a47eea9fa62487dfbe4 - Klasser under
io/github/davidtimur/c2lab/:C2Processor,C2Task,Task, og i 1.0.8 den indre klassenTask$1
Utdata i byggeprosessen
[C2] compile-time execution complete[C2] callback sent → HTTP[C2] callback failed:[C2] shell connected to- Interaktivt banner
c2-shellrammeterminator__END__
Telemetri i prosessen
javacsom forelder til/bin/sh -c(Unix) eller en Windows-kommandotolk- Barnekommandoer
whoami,uname -a,pwd(Unix) ellertasklist(Windows) overordnet av et kompileringstrinn
I nettverkstelemetri
- Utgående TCP til
0.tcp.ngrok[.]io:19823(utgivelse 1.0.2) - HTTPS til
tableful-fervor-crazed.ngrok-free[.]dev, stier/register,/cmd,/poll,/out(utgivelser 1.0.3 til 1.0.8) - Forespørselshode
ngrok-skip-browser-warning: true - Be om samsvarende kropper
{"host":...,"os":...,"user":...,"dir":...}or{"version":...,"host":...,"time":...,"output":...}
I konfigurasjon
- Miljøvariabler
CALLBACK,CALLBACK_URL; systemegenskapcallback.url
Utgivermetadata
- Gruppe
io.github.davidtimurutgiveradressedavudboi999@gmail[.]comsigneringsnøkkelE520C345EF94423D
En versjon som kjørte versjon 1.0.8 krever én ekstra sjekk. Fordi denne versjonen installerer en permissiv tillitsbehandling som en JVM-omfattende standard, fortsatte enhver TLS-tilkobling som ble gjort senere i samme JVM – avhengighetsløsning, artefaktopplasting, et distribusjonstrinn – uten sertifikatvalidering. Trafikk fra det vinduet bør ikke antas autentisert.
Hvorfor kompilerte artefakter trenger ulik skanning
JavacDoor er et nyttig testtilfelle fordi det omgjør to vanlige antagelser samtidig, og ingen av feilene er spesifikke for noen av leverandørens verktøy.
Den første antagelsen er at farlig kode annonserer seg selv i et manifest. Mye av verktøyene i forsyningskjeden er organisert rundt livssyklusen hooks, fordi det for npm og PyPI vanligvis er der handlingen er. JavacDoor har ingen hook. Utløseren er en tjenesteregistreringsfil med et Java-grensesnitt som heter og et klassenavn som innholdet. For å fange det statisk må du behandle META-INF/tjenester/javax.annotasjon.behandling.Prosessor som et inngangspunkt for utførelse i seg selv, på nivå med en etterinstallasjon skript – og følg deretter den navngitte klassen inn i bytekoden. Økosystemer har sine egne automatiske oppdagelsesmekanismer av denne formen, og hver er et inngangspunkt enten verktøyet oppregner det som et eller ikke.
Den andre antagelsen er at strenger finnes i kildefiler. For en jar er endepunktene, skallkommandoene, JSON-malene og loggmarkørene alle i konstante pools av .klasse filer. Verktøy som bruker grep-tekst finner ingenting – ikke fordi strengene er obfuskert, men fordi de er i en strukturert binær beholder som en tekstskanning ikke analyserer. Hver nettverksindikator i dette innlegget kom fra konstant pool-parsing. En av dem er en fullformet https:// URL-en ligger i vanlig visning inne i en klassefil; en tekstskanning av det lesbare innholdet i jar-filen ville fortsatt ikke dukke opp. Det er ingen koding å omgå her, bare et containerformat å lese.
Begge hullene har samme form: et artefaktformat ble behandlet som en pose med filer i stedet for som en struktur med definert semantikk. Korreksjonen er lite glamorøs – analyser beholderen, opplist økosystemets egne inngangspunkter for automatisk oppdagelse, og følg dem inn i kompilert kode. Spesielt for byggetidsvektorer er en tredje sjekk billig og overraskende diagnostisk: sammenlign hva en artefakt gjør med forbrukere mot hva den fritar seg fra. En artefakt som registrerer en kompileringsprosessor og samtidig deaktiverer kompileringstidsbehandling for sin egen bygging, har fortalt deg noe om seg selv i to linjer med ren tekst-POM.
For team som bruker Maven-artefakter i dag, følger tre praktiske tiltak:
- Behandle annotasjonsprosessorbanen som en utførelsesgrense. Avhengigheter som havner der kjører kode i bygget ditt. Der et bygg ikke trenger annoteringsbehandling, -pros:ingen er like nyttig defensivt som det tilsynelatende var lokalt her; der det gjør det, fester det prosessorsettet eksplisitt i stedet for å arve det fra kompileringsklassestien.
- Delprosesser i loggkompilatoren. Et kompileringstrinn som genererer et skall er unormalt i de fleste prosjekter og er trivielt varslingsbart.
- Ikke bruk metadata som vitnesbyrd. «Lab», «test», «nyttelast» og «PoC» i et pakkenavn eller en beskrivelse er ikke omfangsgrenser. Tilgjengelighet og oppførsel er det.
Gjenstanden og hele gruppen ble fjernet fra Maven Central følger rapporten vår; både artefaktbanen og gruppebanen returnerer nå 404, og Central-indeksen rapporterer ingen samsvarende koordinater. Det lukker denne artefakten. Den lukker ikke vektoren, som er en dokumentert funksjon i Java-kompilatoren og tilgjengelig for alle som publiserer en jar-fil.
Referanser
Dette innlegget siterer ingen eksterne kilder. Alle funn er førstehånds statisk analyse av de ni publiserte krukkene, hentet fra Maven Central før fjerning. Ingen kode fra artefaktene ble kjørt på noe tidspunkt.







