Dostałem wiadomość na LinkedInie, która wyglądała dość standardowo, ale oferta była wyjątkowo kusząca.
Napisal niejaki Fabrizio Michele Bressan. Project Manager.
Profil rekrutera. Wyglądał całkiem profesjonalnie, prawda? Zdjęcie na wygenerowane przez AI, ale ostatnio sporo osób robi sobie takie "profesjonalne" headshoty, więc początkowo nie wzbudziło to moich podejrzeń.
Brzmiało to jak złoty strzał. Firma? PokerStars. Projekt? Web3 games. Stawka? $80 - $100 za godzinę. Dla freelancera brzmi jak marzenie. Fabrizio był bardzo konkretny: CV, skill test, rozmowa z technicznym, NDA i jedziemy z koksem. Szybka piłka.
Pierwszy kontakt. Brzmi zachęcająco, konkretnie i profesjonalnie.
Stawka $80-100/h i praca zdalna przy Web3. Brzmi prawie zbyt dobrze, żeby było prawdziwe... i było.
Przesłałem CV. Po chwili odpowiedź:
"CV jest świetne, łap zadanie testowe". Link do repozytorium na Bitbucket. Zadanie: naprawić/rozwinąć backend.
Moment przekazania "zadania rekrutacyjnego". Zwróćcie uwagę na presję czasu i prośbę o "ping" przy starcie.
Pobieram projekt
W końcu udało mi się pobrać repozytorium. Początkowo były problemy z dostępem (link nie działał), ale Fabrizio szybko to ogarnął.
Tak wyglądało repozytorium. Na pierwszy rzut oka - standardowy projekt.
Zwyczajny projekt Next.js... prawie.
Struktura plików wyglądała totalnie standardowo. server, src, package.json, jakiś README.md. Wyglądało to na zwykły sklep/grę w klimatach Web3. Co prawda bardzo niechlujnie napisaną, no ale jednak.
README wyglądało wiarygodnie, instrukcje uruchomienia, opis projektu.
Zależności w package.json też nie budziły podejrzeń na pierwszy rzut oka. React, Next.js, biblioteki krypto.
Zazwyczaj w tym momencie większość z nas robi jedną rzecz:
npm install && npm start
NIE RÓBCIE TEGO. Nigdy.
Zanim odpaliłem cokolwiek, postanowiłem przejrzeć kod. Mam taki nawyk, że sprawdzam package.json i dziwne pliki w folderach. I wtedy mnie zmroziło.
Co znalazłem w kodzie? (Analiza techniczna)
Zamiast naprawiać bugi, znalazłem Backdoora.
W pliku server/middlewares/validator/index.js (brzmi niewinnie, prawda? Walidacja danych...) znalazłem taki kwiatek:
To jest ten moment. Funkcja, która pobiera kod z internetu i wykonuje go przez eval(). Backdoor w czystej postaci.
Co to robi?
- Łączy się z domeną
chainlink-api-v3.com. To nie jest oficjalna domena Chainlinka. To tzw. typosquatting – domena, która udaje legitną. - Wykorzystuje
eval(). Kod pobiera treść z internetu (ukrytą w odpowiedzi błędu HTTP, bardzo sprytne) i natychmiast wykonuje ją na urządzeniu. - Dzieje się to automatycznie przy starcie serwera (IIFE).
Gdybym wpisał npm start, haker miałby w tym momencie pełny dostęp do mojego komputera. Mógłby wyciągnąć klucze prywatne do portfeli krypto, hasła z przeglądarki, klucze SSH. Wszystko.
To nie był koniec. W pliku fileRemover.js znalazłem zakomentowany kod, który wyglądał na próbę steganografii – wyciągania złośliwego kodu ukrytego w pliku graficznym .png.
Zakomentowany fragment sugerujący próbę ukrycia złośliwego kodu w obrazku tła.
A we frontendzie (faucet/index.tsx) skrypt zbierał moje IP i lokalizację, wysyłając je na zewnętrzny serwer.
Frontend po cichu wysyłał moje IP i lokalizację do API atakującego.
Sprawdzam, co siedzi w środku
Dla pewności postanowiłem sprawdzić ten ich "API". Oczywiście wszystko robiłem już na maszynie wirtualnej, żeby nie ryzykować infekcji mojego głównego systemu.
Najpierw spróbowałem zwykłego zapytania curl. Serwer nie zwracał nic ciekawego.
Próba połączenia curlem bez odpowiednich nagłówków. Serwer milczy, udaje, że nie istnieje.
Ale kiedy ustawiłem User-Agent na taki, jakiego używa biblioteka axios (czyli udawałem, że jestem odpalonym skryptem Node.js) – serwer "wypluł" ładunek. Złośliwy skrypt JavaScript.
Bingo. Po zmianie User-Agent serwer myśli, że jestem ofiarą i wysyła złośliwy skrypt.
Finał rozmowy
Wiedziałem już, że to wałek. Ale postanowiłem pociągnąć grę. Napisałem do Fabrizio po 30 minutach: "Skończyłem projekt, możemy się zdzwonić, żeby pokazać rozwiązanie?".
Jego odpowiedź? "Sure. I will contact technical manager". Zero zdziwienia, że zrobiłem "skomplikowane zadanie" w 30 minut. Chodziło tylko o to, żebym uruchomił kod.
Wnioski dla Was
To był scam celowany w programistów ("Job Offer Scam"). Jest coraz popularniejszy, zwłaszcza w branży krypto/web3.
- Nie ufaj rekruterom znikąd, zwłaszcza jeśli oferują gigantyczne stawki i od razu wysyłają pliki/repozytoria.
- Analizuj kod przed uruchomieniem. Zawsze. Szukaj
eval,exec,child_process, dziwnych requestów sieciowych przy starcie serwera. - Używaj maszyny wirtualnej. Jeśli naprawdę musisz zrobić zadanie rekrutacyjne z nieznanego źródła – postaw Sandboxa albo VM-kę bez dostępu do Twoich prywatnych plików.
Uważajcie na siebie. Fabrizio (czy jak mu tam naprawdę na imię) wciąż pewnie szuka "talentów". Nie dajcie się złowić.