Remote code execution (RCE)
CWE-94CWE-77OWASP A03:2021Bijgewerkt 29 augustus 20265 min leestijd
Remote code execution (RCE) is een kwetsbaarheid waarbij een aanvaller op afstand eigen code of systeemcommando's op uw server laat uitvoeren, doordat onveilige invoer in een commando, een tekstsjabloon of een deserialisatie terechtkomt. Het is de ernstigste uitkomst die een applicatie kan hebben: vanaf dat moment draait de aanvaller code met de rechten van uw server.
Remote code execution, kortweg RCE, geldt als de ernstigste uitkomst die een webkwetsbaarheid kan hebben. De aanvaller stuurt niet zomaar gegevens naar uw applicatie, maar zijn eigen programmacode of systeemcommando’s, en uw server voert die netjes uit. Hieronder leest u wat RCE precies is, hoe zo’n aanval in de praktijk verloopt, wat een aanvaller ermee bereikt en hoe u uw applicatie ertegen dichttimmert.
Wat is remote code execution?
Remote code execution (RCE) is een kwetsbaarheid waarbij een aanvaller op afstand eigen code of commando’s op uw server laat uitvoeren. Dat lukt zodra invoer van buitenaf (een parameter, een geüpload bestand, een header) ergens terechtkomt waar de applicatie die invoer als uit te voeren instructie behandelt in plaats van als onschuldige data.
Een alledaagse vergelijking: stelt u zich een gebouw voor met een brievenbus die alleen bedoeld is om een adres op te geven. Achter de bus zit een ijverige assistent die precies uitvoert wat er op het briefje staat. Normaal krijgt hij een adres en zoekt hij de route op. Maar schrijft iemand op het briefje “en zet daarna alle deuren open”, dan doet de al te gehoorzame assistent ook dát. Bij RCE is uw server die assistent: alles wat via een verkeerd bewaakte opening binnenkomt, kan een opdracht worden.
De kwetsbaarheid zit dus niet in één specifieke techniek, maar in het patroon dat invoer en uitvoerbare instructies door elkaar lopen. Dat kan gebeuren wanneer invoer in een systeemcommando belandt (command injection, CWE-77), wanneer een applicatie een string als programmacode evalueert met bijvoorbeeld eval (code-injectie, CWE-94), of wanneer een kwetsbare bibliotheek onvertrouwde gegevens deserialiseert. De rode draad is telkens dezelfde: de grens tussen data en code is weggevallen.
Hoe werkt een RCE-aanval?
De klassieke route is command injection: de applicatie bouwt een systeemcommando op door gebruikersinvoer aan een tekst te plakken en geeft dat aan de shell. Neem een eenvoudige diagnosefunctie die de bereikbaarheid van een host controleert met het ping-commando.
Kwetsbaar:
const { exec } = require("child_process");
app.get("/ping", (req, res) => {
const host = req.query.host;
// Invoer wordt rechtstreeks in het shell-commando geplakt
exec("ping -c 1 " + host, (err, stdout) => {
res.send(stdout);
});
});
Vult een gewone gebruiker een hostnaam in, dan werkt dit prima. Maar exec geeft de hele tekst aan een shell, en die kent speciale tekens. Een aanvaller vraagt niet /ping?host=example.com op, maar /ping?host=example.com;cat /etc/passwd. De shell ziet de puntkomma als scheidingsteken tussen twee commando’s en voert het tweede gewoon uit. Met varianten als host=example.com && rm -rf /data of het binnenhalen en starten van een script verandert dit onschuldige diagnosevenster in een volwaardige opdrachtregel op uw server.
De oplossing is om invoer nooit door een shell te laten interpreteren. Roep het programma rechtstreeks aan en geef de argumenten als een aparte lijst, zodat speciale tekens hun betekenis verliezen. Valideer daarbovenop de invoer tegen een strikt patroon.
Veilig:
const { execFile } = require("child_process");
app.get("/ping", (req, res) => {
const host = req.query.host;
// Alleen letters, cijfers, punten en koppeltekens toestaan
if (!/^[a-zA-Z0-9.-]+$/.test(host)) {
return res.status(400).send("Ongeldige host");
}
// Argumenten gaan als lijst mee, zonder tussenkomst van een shell
execFile("ping", ["-c", "1", host], (err, stdout) => {
res.send(stdout);
});
});
Nu wordt example.com;cat /etc/passwd als één enkele, ongeldige hostnaam behandeld: er is geen shell meer die de puntkomma opvat als “start een nieuw commando”, en de validatie weigert de invoer sowieso. Het programma krijgt exact de argumenten die u bedoelde en niets meer, precies de scheiding tussen commando en data die de aanval onmogelijk maakt.
Wat is de impact van remote code execution?
De impact van RCE is per definitie zwaar, want de aanvaller draait code met dezelfde rechten als uw applicatie. In het gunstigste geval leest hij bestanden uit die niet voor hem bestemd zijn: configuratiebestanden, geheime sleutels, de broncode. Maar meestal blijft het daar niet bij. Met uitvoering van commando’s kan hij een blijvende achterdeur installeren, gegevens versleutelen voor losgeld of de server inzetten als vertrekpunt voor verdere aanvallen.
Vooral dat laatste maakt RCE zo gevaarlijk. Een overgenomen server staat vrijwel altijd binnen uw netwerk en heeft toegang tot zaken die van buitenaf onbereikbaar zijn: interne API’s, databases, andere machines. Van daaruit beweegt een aanvaller zijwaarts door de infrastructuur, verzamelt hij inloggegevens en werkt hij toe naar de systemen die er echt toe doen. Wat begon als één kwetsbaar invoerveld, eindigt dan in een volledige inbraak.
Voor de organisatie betekent dat een datalek, uitval van diensten, mogelijke afpersing en de bijbehorende juridische en reputatiegevolgen. Omdat de ernst varieert van het uitlezen van een enkel bestand tot volledige overname van server en netwerk, loopt de score van hoog tot kritiek, en in de praktijk zit een echte RCE vrijwel altijd aan de bovenkant van die schaal.
Hoe spoort u remote code execution op?
Een tester zoekt naar elke plek waar invoer een commando, een bestandspad, een sjabloon of een deserialisatie kan beïnvloeden. Een eerste controle is het meesturen van shell-tekens als ;, | of && gevolgd door een onschuldig commando, en kijken of de uitvoer verandert. Levert dat geen zichtbaar resultaat op (bij blinde varianten is er geen directe reactie), dan meet een pentester het gedrag indirect: een commando dat de reactie kunstmatig vertraagt, of dat een uitgaand netwerkverzoek naar een eigen server aftrapt en zo de uitvoering verraadt.
Geautomatiseerde scanners en afhankelijkheidscontroles vinden veel bekende gevallen, zoals een kwetsbare bibliotheekversie, maar missen de RCE’s die diep in de eigen logica of achter authenticatie verscholen zitten. Een grondige penetratietest combineert daarom automatisering met handmatig onderzoek. Dit is precies het soort zwakke plek dat AssistSec bij een security-onderzoek gericht opspoort en aantoonbaar reproduceert, zodat u weet welke invoer werkelijk tot code-uitvoering leidt.
Hoe voorkomt u remote code execution?
- Roep externe programma’s aan zonder shell. Gebruik een variant die het programma en zijn argumenten als aparte lijst meegeeft (zoals
execFilein plaats vanexec), zodat speciale tekens geen betekenis krijgen. - Evalueer nooit onvertrouwde invoer als code. Vermijd
evalen vergelijkbare constructies op basis van gebruikersinvoer, en gebruik veilige sjabloon-engines die data en code scheiden. - Valideer invoer met een witte lijst. Bepaal per veld welke waarden geldig zijn en weiger de rest, in plaats van te proberen “gevaarlijke” tekens weg te filteren.
- Houd afhankelijkheden bij en patch snel. Veel RCE’s komen uit externe componenten; volg advisories en werk kwetsbare versies zo snel mogelijk bij.
- Pas het principe van minste rechten toe. Laat de applicatie draaien onder een account met minimale rechten en in een geïsoleerde omgeving, zodat een geslaagde aanval zo min mogelijk kan bereiken.
- Wees voorzichtig met deserialisatie en bestandsuploads. Deserialiseer geen onvertrouwde gegevens en behandel geüploade bestanden nooit als iets dat uitgevoerd mag worden.
- Laat de code periodiek testen. Een gerichte penetratietest en code review vangen de RCE-paden die scanners overslaan.
Bronnen
Veelgestelde vragen
Wat is het verschil tussen RCE en command injection?
Command injection is een van de meest voorkomende wegen naar remote code execution: onveilige invoer belandt in een systeemcommando. RCE is de bredere uitkomst (code uitvoeren op afstand) die ook via code-injectie, onveilige deserialisatie of een kwetsbare bibliotheek kan ontstaan.
Waarom is RCE zo veel ernstiger dan andere kwetsbaarheden?
Bij de meeste kwetsbaarheden leest of wijzigt een aanvaller gegevens. Bij RCE draait hij zijn eigen code op uw server, met dezelfde rechten als uw applicatie. Daarmee is in principe alles op die machine bereikbaar, en vaak de rest van het netwerk erachter.
Kan een RCE ontstaan zonder dat ik zelf onveilige code schrijf?
Ja. Veel RCE's komen uit een kwetsbare externe bibliotheek of component. Log4Shell is het bekendste voorbeeld. Bijhouden welke afhankelijkheden u draait en tijdig patchen is daarom net zo belangrijk als veilige eigen code.
Beschermt een web application firewall tegen RCE?
Een WAF vangt bekende aanvalspatronen af en is een nuttige extra laag, maar aanvallers omzeilen filters regelmatig met andere codering of onbekende payloads. De echte oplossing zit in veilige aanroepen, invoervalidatie en tijdig patchen.
Verwante artikelen
- CVE'sCWE-917A03:2021Log4Shell (CVE-2021-44228)Log4Shell uitgelegd: hoe één regel tekst in een logbestand code op uw server uitvoerde, wie het misbruikte en wat u vandaag nog moet controleren.
- CVE'sCWE-77A03:2021PAN-OS GlobalProtect (CVE-2024-3400)CVE-2024-3400 uitgelegd: hoe een commando-injectie in de GlobalProtect-gateway van PAN-OS aanvallers rootrechten op de firewall gaf.
- BegrippenPentestEen pentest is een gecontroleerde aanval op uw systemen door ethische hackers. Lees hoe een penetratietest werkt en welke kwetsbaarheden u ermee vindt.
- KwetsbaarhedenCWE-16A05:2021Security misconfigurationSecurity misconfiguration uitgelegd: hoe standaardwachtwoorden, debug-modi en open cloud-buckets aanvallers binnenlaten, en hoe u dit voorkomt.
- KwetsbaarhedenCWE-89A03:2021SQL injectionSQL injection uitgelegd: hoe aanvallers via ongefilterde invoer uw database uitlezen of wijzigen, en hoe u het met prepared statements voorkomt.
- KwetsbaarhedenCWE-918A10:2021Server-side request forgery (SSRF)Server-side request forgery (SSRF) uitgelegd: hoe aanvallers uw server dwingen interne systemen en clouddiensten te bereiken, en hoe u het voorkomt.